JSON-RPC の文字コードの取り扱い
サーバ側に Python + json-rpc モジュール、クライアント側に jsolait を利用して
JSON-RPC によるメソッド呼び出しのテストを細々とやっていたのですが、
#!C:/Python25/python.exe #coding:utf-8 from jsonrpc import handleCGI, ServiceMethod import sys @ServiceMethod def echo(msg): return msg handleCGI()
たったこれだけのコードが動かなくて悩みました。
正確には日本語を使おうとすると動かなくて悩みました。
最初は、サーバ側プログラムのエラーで http のレスポンスの 500 が返って来てまして、
調べてみるとどうやら ascii コーデックが日本語を扱えないとおっしゃる。
これに関しては、python25/lib/site-packages/ に sitecustomize.py というファイルを置き、
import sys sys.setdefaultencoding("utf-8")
と中身にこんなコードを書くことで解決。これは みんなのPython に載っておりました。*1
再び実行してみると今度はクライアント側で、なぜかパース出来ない、というエラーが。
buf=StringIO() handleCGI(fout=buf) f=open("log.txt","w") f.write(buf.getvalue()) f.close() print buf.getvalue()
といったコードを書いて実際どんなレスポンスを返しているのか見てみると、
Content-Type: text/plain Content-Length: 44 {"error":null,"result":"あああ","id":"httpReq"}
んー、実際の文字列のサイズは 47 byte なんですが、 Content-Length は 44, これは文字数ですかね。
jsonrpc のモジュールのコードを追っかけてみると、案の定ユニコード文字列の長さを
Content-Length として返しておりました。ライブラリのコードを直接書き換えて、ユニコード文字列を
一度 utf-8 の文字列に変換してから長さを取るようにしてみたらクライアント側のエラーもなくなりました。
response = "Content-Type: text/plain\n" # cgiwrapper.py の 28 行目 #response += "Content-Length: %d\n\n" % len(resultData) response += "Content-Length: %d\n\n" % len(resultData.encode(sys.getdefaultencoding())) response += resultData
とりあえずこれで次に進めるかなぁ。
*1:実は最初はこの方法でなぜか問題が解決しませんでした。でも今日もっかいやったら解決しました。謎です。