はてなブログに記事を投稿するプログラムを書いていたら、ハマったことがあったのでメモしておきます。
誰かのためになれば
はてなブログAtomPub
はてなブログAtomPubはここにあります。 ドキュメントがキレイになってる。はてなだけはAPIを提供し続ける気持ちがありそうだ。
https://developer.hatena.ne.jp/ja/documents/blog/apis/atom
使った環境
- Laravel Framework 10.48.4
- HTTPファサード
エラーになったプログラム
LaravelのHTTPファサードを使ってxml文字列をポストするだけです。はてなのAPIはベーシック認証が必要です。はてなブログの設定画面から確認できます。
//XMLはシンプルにvalidになるものを $xml = '<entry></entry>'; $response = Http::withBasicAuth($username, $api_key)->post($endpoint, $xml); var_dump($response->status()); var_dump($response->body());
エラーの内容
400 XML Parse Failed
プログラムで作ったXMLのパースエラーが出たので、上のプログラムのように極限までシンプルなXMLにしたのにパースエラー。エラーになる要素、ないだろ!?
しかし、プログラムから作ったXMLをVS CodeのHttp Clientで投げ込むと成功する。
全く分からなかった。
解決のヒント
http通信をデバッグにしてみたら、content-length
が18バイトだった。送っているXML(<entry></entry>
)は15バイトである。おかしいな、3バイト多いぞ。
3バイト多いって言ったら、BOMかもな?
作った文字列と送信したデータの違いを見る方法を探すことができなかったので、BOMの疑いがある、というところまで。
解決した方法
Postメソッドにxmlを入れるのではなく、HttpファサードのwithBodyでxmlを指定してみたら、上手くいった。
//XMLはシンプルにvalidになるものを $xml = '<entry></entry>'; $response = Http::withBasicAuth($username, $api_key)->withBody($xml)->post($endpoint); var_dump($response->status()); var_dump($response->body());
エラーメッセージ
400 Entry Title required
「エントリーにタイトルが必須です」エラーに変わったので、XML自体は読み込んでもらえたっぽい。
Content-Length
も15バイトになったし、やっぱりBOMだったんだろうな。postメソッドで文字列にBOMを付けない方法があればいいのだけど、解決したからよしとする
参考にした資料
BOMに疑いありなことを見つけたサイト
PUT/POSTリクエストで400 XML Parse Failedが返される不具合に対する対処として、はてなブログAtomAPIに送信するXML文書を常にBOMなしのUTF-8とするように修正
https://smdn.jp/works/tools/HatenaBlogTools/#changes_v3.1
withBodyで書けばよいことを見つけた記事
https://stackoverflow.com/questions/60318425/posting-xml-using-guzzle-client-laravel