ふにゃるんv2

もとは、http://d.hatena.ne.jp/Wacky/

XML-RPCでメッセージに日本語を通す方法

pythonXML-RPC対応って、むっちゃ簡単だよね。

  • サーバ側:SimpleXMLRPCServer.SimpleXMLRPCServer で、公開したい関数 or クラスを登録するだけ
  • クライアント側:xmlrpclib.ServerProxy で、呼び出したい関数をコールするだけ

動かす際、Apacheとか何かと連携しないといけないのかと思ったら、全然そんな事なくて、単に書いて python hoge.py という風に呼び出すだけ。
DCOMやCORBAだと、色々 あれこれ しないといけないのに、「何これ?卑怯じゃん。漏れ、すっげー損してたよ!」って感じ。


で、早速遊んでいたら、string(文字列)引数に、日本語を突っ込んだら、エラーが発生する事に気付いた。

...
  File "/usr/lib/python2.4/xmlrpclib.py", line 1096, in __call__
    return self.__send(self.__name, args)
  File "/usr/lib/python2.4/xmlrpclib.py", line 1383, in __request
    verbose=self.__verbose
  File "/usr/lib/python2.4/xmlrpclib.py", line 1137, in request
    headers
xmlrpclib.ProtocolError: <ProtocolError for localhost:8000/RPC2: 500 Internal error>

さっそく ぐぐーる様に お伺いを立てるが、あまり言及する資料が無い。
メーリングリストで、自分と同じ現象で困っている人が居たくらい。

[Python-ml-jp 1497] xmlrpclibで日本語を扱うには?
http://www.python.jp/pipermail/python-ml-jp/2002-June/001494.html
Morf-hine : はてなダイアリーキーワード自動リンクAPI
http://www.zoili.net/203


う〜ん、あんまり日本語を通す要求って無いのかしらん?と思って、サーバとクライアントの両方をUTF-8にしたりして、トライ&エラーで、試してみた。


で、結局の所、
XML-RPCで日本語を通すには、UTF-8に変換して通す必要がある
という事がわかった。


という訳で、実証コードね。

server.py:
# -*- encoding: euc_jp -*-
import commands
import sys
import re
import  SimpleXMLRPCServer

def test(msg):
    print type(msg), len(msg)
    if type(msg) is unicode:
        print msg.encode("euc_jp")
    else:
        print msg
    return 0

def main():
    srv = SimpleXMLRPCServer.SimpleXMLRPCServer
    srv.register_introspection_functions( ) 
    srv.register_function(test)
    print "listen"
    srv.serve_forever()

if __name__ == "__main__":
    main()
client.py
# -*- coding: euc_jp -*-
import commands
import sys
import re
import xmlrpclib


def main():
    print sys.stdout.encoding
    print sys.getfilesystemencoding()
    srv = xmlrpclib.ServerProxy("http://localhost:8000")
    print srv.system.listMethods()
    while True:
        c = raw_input(">")
        if c == "q": break
        s = unicode(c, "euc_jp", "ignore").encode("utf-8")
        print type(s), len(s)
        print srv.test(s)

if __name__ == "__main__":
    main()

実行結果。(Python 2.4.1 for Cygwinでテスト)

クライアント側:
$ python client.py
US-ASCII
US-ASCII
['system.listMethods', 'system.methodHelp', 'system.methodSignature', 'test']
>ほげ
<type 'str'> 6
0
>hoge
<type 'str'> 4

サーバ側:
$ python server.py
listen
localhost - - [11/Sep/2005 12:20:38] "POST /RPC2 HTTP/1.0" 200 -
<type 'unicode'> 2
ほげ
localhost - - [11/Sep/2005 12:20:47] "POST /RPC2 HTTP/1.0" 200 -
<type 'str'> 4
hoge
localhost - - [11/Sep/2005 12:21:03] "POST /RPC2 HTTP/1.0" 200 -

当初、MLの内容から、コード自体をUTF-8で記述しないといけないのか?と思ってたんだが、そこまでする必要は無く、実際、検証コードも、EUCで記述している。
送受信時、ちと手間な変換作業が発生するが、まぁ 許容範囲でしょう。