読者です 読者をやめる 読者になる 読者になる

Chonaso's Commentary

InternetやIT技術などについて知ったこと、試したこと、考えたことを書いていきます。

不作法なWebAPIにハマる

HTTP Java ハマリ

プロダクトコードなので詳細は非公開ですが、とあるパブリックじゃないWebAPIへのアクセスで激ハマりしたのでその記録などひとつ。

そのWebAPIの仕様書(のようなもの)にはレスポンス内の文字コードについての言及がなく、「メッセージは英語なのかな」って勝手に思い込んでいたのですが、先方の試験用環境にアクセスしたら思いっきりマルチバイト文字だった、というところから始まりました。

完全に文字化けしていてどうしようもない状態だったので、先方に「これ文字コード何ですか?」と確認したら「シフトJISです(ぺこり)」との回答。

ならば、ちょろっと.getBytesして文字コード変換すればいいかな、と思いましたが、妙な違和感。

そもそもhttpclient使っている系のライブラリでこの手の問題(文字化け)って出くわした(解決した)記憶がないのです。

レスポンスの文字コード周りは普通はライブラリがうまく処理してくれるはずですが、まさかと思ってレスポンスの中身を見てみると…

HTTP/1.1 200 OK
Date: Sat, 18 Oct 2014 00:00:00 GMT
cache-control: no-catch
Connection: close
Content-Type: text/plain
Set-Cookie: xxxxxxx=xxxxxxxxxxxxxxxxxxx; Path=/

(Shift_JISな本文)

charsetがありませんでした。\(^o^)/

あと、最初スルーしてたけどよく見たらno-cacheじゃなくてno-catchだし!

Content-Type: text/plain;charset=Shift_JIS

みたいに返してくれていたらなんの問題もなく、「へー日本語なのね」って程度で済んだでしょうね。

さすがにBody部を見て文字コードを自動判別してくれるほどの親切機能はhttpclientには無いので自力でどうにかする必要が出てきました。

とりわけ文字コード関連はJavaの中で理解しづらい領域で、正しい文字コードが分かってても解決がなかなか大変。パイプの最後にiconvを持ってくれば済むようにはいかないわけです。

結局、一番入口の部分で適切な文字コードを指定してやらないとならないのですが、

  • デフォルトだからISO-8859-1っぽいワードを探して、
  • そこから変換やってそうな処理を探して、
  • 大雑把にブレイクポイント打って、
  • ステップステップ…で場所を特定して、
  • 文字コード指定できるサブクラスを作って…と思ったらfinalなんで別のクラス作って、
  • それを呼び出すFactoryクラスも別なのを作って…

という感じでなんとか問題は解決しましたが、コード読み力が相当落ちてしまっているので存外苦戦してしまいました。

全く邪魔の入らない休日だったから対応できましたが、平日だったら絶対無理ですね...

まとめとしては、WebAPIを提供する場合はヘッダ周りもちゃんと気を使いましょう、というところです。一度公開しちゃうと些細な変更・修正もやりづらいですしね。

余談1

これ、Windows環境だとSJISが普通に食えちゃうので文字化けしないケースだったりします。こういうのに出くわすと開発環境もやっぱりLinuxMacにしたものか、って考えてしまいますね。

余談2

面倒だからApacheでプロキシしてmod_headers使って強制的にヘッダ書き換えちゃおうか、と試してみましたが、レスポンスのContent-Typeにはmod_headersが効かないという全くの無駄足でした。

プログラマのための文字コード技術入門 (WEB+DB PRESS plus) (WEB+DB PRESS plusシリーズ) 文字コード「超」研究 改訂第2版 図解雑学 文字コード (図解雑学シリーズ) 図解入門 よくわかる最新ファイル形式と文字コードの基本と仕組み―データ形式、ファイル構造、文字コード基礎講座 (How‐nual Visual Guide Book) 図解でわかる文字コードのすべて―異体字・難漢字からハングル・梵字まで パソコンにおける日本語処理・文字コードハンドブック