Top > xmlrpc

XMLRPC 使用上の注意点

システム間結合をする際 XML-RPC という便利な仕様があります。この仕様はよくできていて、仕様が軽量である上に、よほどのことがなければトラブルは起こらないでしょう。以下は少ないトラブルのうち、実際に経験した内容です。

double

XMLRPC の浮動小数点数型である double では、仕様をざっくり要約すると「無限大の表現はない。符号と数字とピリオドのみで空白は含まれない。値の範囲は実装依存。」ということになっています。

Python の xmlrpclib では、XMLRPC の浮動小数点数型である double の出力は repr() で生成するので、精度は 17 になります(浮動小数点)。また repr() は 2.23e-05 といった XMLRPC 仕様に適合しない文字列表現を出力することがありますが、実用上は問題ありません。余談になりますが str() でも浮動小数点数を文字列に変換した場合の精度は 12 で、また%演算子を使ったフォーマットを使うとそれ相応の精度に切り詰められます。decimal を使うと高精度が扱えますが、システム間結合を目的としている XMLRPC では通信先での受け入れができなければ意味がないので、これが登場することは稀でしょう。

PHP の xmlrpc extension では XMLRPC の浮動小数点数の出力は zval から取得(Z_DVAL_P を使用)し、それを ap_php_snprintf の %.*G でフォーマットしますので php.ini の precision に依存します。つまりデフォルトでは精度は 14 になります。こちらも NAN, INF, -INF や 2.23E-5 といった文字列を出力することがありますが、実用上は問題ないでしょう。面白いことに Python, PHP 間で指数表現形式は異なります。

Java での代表的な実装である Apache WS XML-RPC v3.0 では double の出力には Double.toString(double) を使っています。64bit の double なら Python と同様の精度 17 になります。面白いことに Python と Java では異なる表現を出力することがあります。個人的には Python が一風変わっていると思います。

Python 2.6, 3.0

>>> repr(0.000000023)
'2.3000000000000001e-08'

Java 1.6.0_10

class hoge {
 public static void main(String[] argv){
  System.out.println(0.000000023);
 }
}
> java hoge
2.3E-8

いずれにせよ XMLRPC のオリジナル仕様のままでは、浮動小数点数の精度落ちは避けられません。精度を確実に保持したいのであれば、base64 型を使って解釈をアプリケーション側で規定するか、XMLRPC 仕様を拡張して浮動小数点数の表現に hex 形式を使うかしなければなりません。

dateTime.iso8601

ISO 8601 の仕様は 2 回改定が行われていて、改定のたびに表現形式が増えています。XML-RPC でのシステム間結合時に全てのフォーマットに対応するのは現実的ではありません。秒単位までの精度表現が使われて、いくつかの限定されたフォーマットにのみ対応しているのが実情です。

世の中で日付形式として一般的に採用される傾向にあるのが、2009-01-07T12:45:32+09:00 といったフォーマットです。困ったことに XML-RPC 仕様で例として挙げられている形式はこれとは異なり、19980717T14:08:55 という形式になっていて、多くの実装はこれに倣っています。この形式の問題点は TIMEZONE が与えられないことで、XML-RPC 仕様では、それぞれのサーバがどの TIMEZONE を使うかを明示的に宣言するとされています。うっかり油断していると、システム間での TIMEZONE の違いに起因して正しく時刻を伝えられないかもしれないので、注意が必要です。個人的には TIMEZONE つきで通信してしまうのがいいと思っています。

PHP xmlrpc extension の実装では、5.2.7 以降 TIMEZONE がつくようになりました。ちなみに XMLRPC datetime 型の timestamp メンバー変数は PHP 5.2.9 以前では誤った値になっているので、strtotime を使って scalar メンバー変数から変換することで正しい timestamp が得られます( PHP report, XMLRPC-EPI report, XMLRPC-EPI patch)。5.2.10 以降は修正されています。

// output
$a=date('c');
xmlrpc_set_type($a,'datetime');
// input
$data=xmlrpc_decode($xml);
$timestamp=strtotime($data->scalar);

Python xmlrpclib の実装でも出力時に TIMEZONE はつかない(仕様)上に、入力受け取り時も time.strptime(data, "%Y%m%dT%H:%M:%S") としているので失敗します(バグ)。

system.multiCall

XML-RPC の拡張仕様のひとつに system.multiCall というものがあります。仕様自体は本来は xmlrpc.com にあったはずなのですが、長らく消失したままなので、現在は WebArchive などのサービスで探すしか手段がありません。Python の xmlrpclib では、 system.multicall と小文字で実装されています。また PHP xmlrpc extension の下位レイヤライブラリ xmlrpc-epi においては system.multiCall と大文字で実装されているので注意が必要です。個人的には他のメソッド命名規則に合わせると大文字が自然だと思いますが、おそらく不幸な行き違いにより現在の状況に至っていると推測されます。

なお PHP 5.2.12 以前にはバグがあり、system.multiCall の呼び出しを行うと PHP がクラッシュします。必要であれば対応するパッチは入手できますが、PHP のバージョンアップを優先的に検討してください。

追い討ちをかけるようですが system.multiCall でリクエストをシリアライズすると、通常シリアルにしか実行されないので、むしろパラレル化を行ったほうがシステム結合において全体のレスポンスタイム短縮化に寄与することが多いです。この拡張仕様を積極的に使う理由は特にないかもしれません。

UTF-8

XML-RPC はその名のとおり XML をベースにしているので、本来 XML 仕様にあるとおり UTF-8 を扱うことができなければなりません。ところが、いくつかの誤った実装では XML 仕様に違反していて、UTF-8 でエンコードされた XML-RPC 通信を受け付けません。

Apache WS XML-RPC 2.0 は、この問題を抱えています。標準では jar に同梱されている MinML という SAX パーサを使って XML を読み込みますが、同梱されているこのパーサは文字セット指定を無視するという致命的なバグがあることが知られています。MLでの発言によると MinML の将来的なバージョンで対応する予定があるようですが、現時点では対応されていません(ちなみに現在の XML-RPC 仕様では文字列として ASCII 以外も許可されています)。対処法としては SAX パーサを標準ではないもの、たとえば xerces に切り替える方法があります。

XmlRpc.setDriver("xerces");

この他にも、次のような名前で SAX パーサのクラスを切り替えられるようになっています。

名称クラス名
xercesorg.apache.xerces.parsers.SAXParser
xpcom.jclark.xml.sax.Driver
ibm1com.ibm.xml.parser.SAXDriver
ibm2com.ibm.xml.parsers.SAXParser
aelfredcom.microstar.xml.SAXDriver
oracle1oracle.xml.parser.XMLParser
oracle2oracle.xml.parser.v2.SAXParser
openxmlorg.openxml.parser.XMLSAXParser

現行の Apache WS XML-RPC 3.0 では XML パーサ部は Java5 で標準化された JAXP つまり javax.xml.parsers.SAXParserFactory に基づいて実装されていて、デフォルトでは Sun の SAX パーサが使用されますので、この問題は起こらないでしょう。余談ですが JAXP でも必要であれば SAX パーサを切り替えることができます。

HTTP Status code

XMLRPC においては HTTP 通信路は、まさに通信路でしかありません。HTTP ステータスコードは常に 200 です。それ以外のステータスコードが返された場合は、XMLRPC としては「通信路が壊れた」状態です。XMLRPC において HTTP ステータスコードについて言及するのは、ちょうど HTTP において TCP について言及するのと同じことです。


リロード   新規 下位ページ作成 編集 凍結 差分 添付 コピー 名前変更   ホーム 一覧 検索 最終更新 バックアップ リンク元   ヘルプ   最終更新のRSS
Last-modified: Wed, 24 Sep 2014 17:02:51 JST (1124d)

© 2006-2008 Internet Revolution