連載
» 2003年01月17日 00時00分 公開

Webサービスのキホン(3):SOAPヘッダの役割とSOAP-RPCの実現

Webサービスの基軸を構成するのは、SOAP、WSDL、UDDIの3つのテクノロジだ。この連載では、Webサービスの基本的な知識を身に付けるために、この3つのテクノロジの背景と仕様、機能などを分かりやすく解説していく。(編集局)

[吉田稔, 青木秀起,株式会社日本ユニテック]

SOAP拡張のかぎを握るヘッダ

 前回「SOAPという封筒の内部構造」では、SOAPの内部構造とメッセージ本体を中心に紹介した。今回は、SOAPのヘッダについて解説する。

 SOAPメッセージのヘッダには、SOAPメッセージを処理するアプリケーションが機能を拡張するために、独自に定義する要素・属性を格納できるようになっている。例えば、認証などのセキュリティ情報、トランザクション情報、セッション情報といった、SOAPボディでは直接扱うことのできない情報を記述することが考えられる。

図1(第2回から再掲) プロトコルバインディングされたSOAPメッセージの構造(分かりやすくするため、名前空間などの指定は省略してある) 図1(第2回から再掲) プロトコルバインディングされたSOAPメッセージの構造(分かりやすくするため、名前空間などの指定は省略してある)

 要求/応答メッセージを例に、セッション情報が必要な理由を考えてみよう。要求/応答のセットをサポートしていない通信プロトコルを使用する場合や、要求メッセージと応答メッセージが別のセッションでやりとりされる場合、要求メッセージと応答メッセージの対応関係を取れなくなってしまう。

図2 要求/応答メッセージの実装例 図2 要求/応答メッセージの実装例

SOAPヘッダでセッション管理

 そもそもSOAPは、一方向で1回限りのメッセージ送信が基本で、直前の通信状態を保持しない(すなわちステートレスな)プロトコルだ。しかしそれでは図2のような場合に、返信された応答メッセージを、それに対応する要求メッセージと関連付けることができない。この問題は、ヘッダ部分にメッセージIDを付加して対応関係を作ることによって解消できる。見積もり依頼サービスを要求するメッセージの例をご覧いただきたい。

<?xml version="1.0" encoding="shift_jis"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  
<soapenv:Header>
    <n:MsgHeader xmlns:n="http://unitec-denki.utj.co.jp/requestresponse">
      <n:MessageId>uuid:09111432-123b-5555-c787-2san15pip5e6</n:MessageId>
    </n:MsgHeader>
  </soapenv:Header>
  <soapenv:Body>
    …………
  </soapenv:Body>
</soapenv:Envelope>
リスト1 見積もり依頼サービスの要求メッセージ(色の濃い文字がSOAPヘッダ)

 このリストでは、見積もり依頼サービスのアプリケーションが独自に拡張したMsgHeader要素やMessageId要素が、メッセージIDを管理するためにSOAPヘッダの中で使用されている。対応する応答メッセージは、以下のようになる。

<?xml version="1.0" encoding="shift_jis"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  
<soapenv:Header>
    <n:MsgHeader xmlns:n="http://www.unitec-denki.utj.co.jp/schema/2002/">
      <n:MessageId>uuid:09111432-123b-2392-p423-9add28pon3j1</n:MessageId>
      <n:ResponseTo>uuid:09111432-123b-5555-c787-2san15pip5e6</n:ResponseTo>
    </n:MsgHeader>
  </soapenv:Header>
  <soapenv:Body>
    …………
  </soapenv:Body>
</soapenv:Envelope>
リスト2 見積もり依頼サービスの応答メッセージ(色の濃い文字がSOAPヘッダ)

 この応答メッセージでは、SOAPヘッダ内に埋め込まれたResponseTo要素に要求メッセージのメッセージIDが格納されている。このメッセージIDによって、これが先ほどの要求メッセージに対する応答メッセージであるということを識別できる。

 また、セキュリティ情報をヘッダ部分に格納することもできる。現在のところ、SOAPを利用したセキュアな通信の実現には、SSL/TLSやS/MIMEなどによって通信プロトコル上のセキュリティを確保する方法が一般的だが、ヘッダ部分にデジタル署名を組み込むことにより、コンテンツ自体を暗号化するとセキュリティをさらに強化できる。これが「SOAP Security Extensions: Digital Signature」(W3Cの技術ノート)と呼ばれる拡張機能だ。例えば、クレジットカード番号などが入った本体部分だけを暗号化し、暗号化アルゴリズムなど復号に必要な情報をヘッダ部分に格納できる。

 このほかの拡張機能として、ファイル添付機能 (「SOAP 1.2 Attachment Feature」(W3Cワーキングドラフト))もある。この機能では、MIME構造を使って非XMLデータをSOAPメッセージに添付できる。

 SOAPの機能を拡張してさまざまな通信パターンに柔軟に対応する際に、拡張性に優れたSOAPヘッダは大きな役割を果たしている。現段階ではまだ策定中の仕様が多いが、ヘッダ機能の充実度がSOAPメッセージの使い勝手を左右するといっても過言ではないだろう。

リモートプロシージャコール(RPC)を表現する

 ここまで、SOAPの一方向メッセージや要求/応答メッセージを考えてきたが、SOAPの重要な応用分野がリモートプロシージャコール(Remote Procedure Call:RPC)だ。SOAPメッセージではRPCを表現する方法を定めており、リモートサーバ内のメソッドをあたかもローカルなメソッドのように呼び出すことができる。

 例として次のメソッドをSOAPを使ったRPCで呼び出すことを考えよう。

float GetLastTradePrice(String Symbol)

 これは、パラメータSymbolによって指定された銘柄の株価の終値を、浮動小数点で返すメソッドだ。SOAPではRPCを記述する約束事として、要求メッセージの要素名はRPCで呼び出すメソッド名と同じにすること、またパラメータはその子要素とすることが決まっている。従って、例として用いるメソッドの要求メッセージは以下のようになる。

<?xml version="1.0" encoding="shift_jis"?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2001/12/soap-envelope">
  <soapenv:Header>
    ………
  </soapenv:Header>
  <soapenv:Body>
    <r:GetLastTradePrice ←メソッドから取られた要素名
soapenv:encodingStyle="http://www.w3.org/2001/12/soap-encoding"
xmlns:r="http://example-stock.utj.co.jp/2001/06/quotes">
      <r:Symbol>DEF</r:Symbol> ←パラメータ名から取られた要素名
    </r:GetLastTradePrice> ←メソッドから取られた要素名
  </soapenv:Body>
</soapenv:Envelope>
リスト3 SOAPによるRPC要求メッセージ 

 SOAP仕様によると、RPCの応答メッセージの要素名は、呼び出すメソッド名に“Response”という文字列を付けることが慣例になっている。上記のRPC呼び出しに対する応答メッセージは、以下のようになる。

<?xml version="1.0" encoding="shift_jis"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    ………
  </soapenv:Header>
  <soapenv:Body>
    <r:GetLastTradePriceResponse soapenv:encodingStyle="http://www.w3.org/2001/12/soap-encoding"
xmlns:r=http://example-stock.utj.co.jp/2001/06/quotes>
      <Price>34.5</Price>
    </r:GetLastTradePriceResponse>
  </soapenv:Body>
</soapenv:Envelope>
リスト4 SOAPによるRPC応答メッセージ  

 リスト4において、パラメータ名から取られたPrice要素の内容が戻り値として株価の終値を表している

 SOAP 1.2では戻り値の入る要素の要素名を指定するため、空ではない戻り値があるときに使用するresultという要素が追加された。この使い方は多少複雑だ。まず、xmlns:rpc=http://www.w3.org/2002/06/soap-rpcと名前空間の指定を行う。その名前空間接頭辞(リスト5ではrpc)で修飾されたrpc:result要素に「戻り値の入る任意の要素名」が格納される。そしてこの「戻り値の入る任意の要素名」の要素に「戻り値」が格納される。ただし、戻り値が空の場合はresult要素があってはならない。リスト5は、リスト4の一部にSOAP 1.2の仕様を反映した結果だ。

<r:GetLastTradePriceResponse soapenv:encodingStyle="http://www.w3.org/2001/12/soap-encoding"
xmlns:r=http://example-stock.utj.co.jp/2001/06/quotes
xmlns:rpc=http://www.w3.org/2002/12/soap-rpc>
  <rpc:result>r:price</rpc:result>
  <r:price>34.5</r:price>
リスト5 SOAP 1.2の場合のRPC応答メッセージ

中継サーバを経てSOAPメッセージが送られる場合

 SOAPメッセージは、最初にSOAPメッセージを送信するサーバから最終的なあて先のサーバに、ダイレクトに送られるとは限らない。途中でSOAPメッセージを受け取って、ログ情報などを書き込んでから最終的なあて先のサーバへ転送されることもある。このように最初のSOAP送信サーバと最終的なSOAP受信サーバの中間に存在して、SOAPメッセージを解析するサーバのことをSOAP仲介者(Intermediary)と呼ぶ

図3 SOAPメッセージを中継するサーバがあるケース 図3 SOAPメッセージを中継するサーバがあるケース

 SOAP仲介者はSOAPメッセージの最終的なあて先ではないので、一般にSOAP本体の情報を書き換えることはない。しかし、ログ情報などの付加的な情報をSOAPメッセージに付与することはあるだろう。SOAPヘッダは、このような付加的な情報を書き込む場所としても利用されることがある。

 SOAP仲介者を経由してSOAPメッセージが送られる場合、SOAP仲介者はSOAPメッセージのヘッダ情報をすべて理解する必要はない。例えば、メッセージの一部が暗号化されていて暗号化情報がSOAPヘッダに格納されていることがある。その場合、SOAPヘッダに格納された暗号化情報を使う必要があるのは最終的なSOAP受信サーバだけだ。

 従って、SOAPヘッダの特定の要素を処理する必要があるかどうかをSOAP仲介者に知らせる仕組みがないと、途中のサーバがヘッダ情報を処理できずにエラーを出してしまい、SOAPメッセージが最終的なSOAP受信サーバまで届かない可能性がある。

図4 特定のヘッダ処理ができないサーバがあるとメッセージが届かないことがある 図4 特定のヘッダ処理ができないサーバがあるとメッセージが届かないことがある

 こうした問題を回避するため、SOAPヘッダ内の要素にactor属性(SOAP1.2ではactor属性ではなくrole属性を使って同様の指定を行う)という属性を付与して、どのSOAPサーバがその要素を処理すべきかを指定できる。例えば、ある途中のサーバがリスト6のようなSOAPメッセージを受信すると、actor属性に指定された“http://www.unitec-denki.utj.co.jp/Gateway”というURIのサーバ以外は、r:Redirection要素を処理せず、SOAPメッセージをそのまま次のサーバに転送することになる。

<?xml version="1.0" encoding="shift_jis"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <r:Redirection
xmlns:r="http://www.unitec-denki.utj.co.jp/ Redirection"
soapenv:actor="http://www.unitec-denki.utj.co.jp/Gateway">Business Dept.</r:Redirection>
  </soapenv:Header>
  <soapenv:Body>
    ………
  </soapenv:Body>
</soapenv:Envelope>
リスト6 actor属性の記述例  

 さらに、actor属性以外にも、サーバがSOAPヘッダ内のある要素を処理できない場合、エラーにするのか、気にせずに次のサーバに転送するのかを指定するmustUnderstand属性がSOAPには用意されている。

 mustUnderstand属性は、SOAP受信者がヘッダ項目を必ず処理しなければならないのか、処理が任意であるのかを指定する属性だ。要素の処理が必須である場合には“1”を、要素の処理が任意である場合には“0”(デフォルト値)を指定する(SOAP 1.2では、mustUnderstand属性の値は “true”(必須)または“false”(任意)に変更されている)。例えば、リスト7のように指定した場合、すべてのSOAP受信者はヘッダ項目を必ず解釈して処理しなければならない。

<?xml version="1.0" encoding="shift_jis"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <r:Redirection
xmlns:r="http://www.unitec-denki.utj.co.jp/ Redirection"
soapenv:mustUnderstand="1">Business Dept.</r:Redirection>
  </soapenv:Header>
  <soapenv:Body>
    ………
  </soapenv:Body>
</soapenv:Envelope>
リスト7 mustUnderstand属性の記述例  


 今回はSOAPヘッダと拡張機能、そしてRPC呼び出しや中継サーバを経由する場合などの応用分野を考察した。SOAPがシンプルで合理的な設計を持ちつつも拡張性に優れていることを理解していただけただろう。

 さて、Webサービスを動的に結合するには、SOAPによるメッセージ・フレームワークだけでなく、Webサービスのインターフェイスを共通にすることが必要だ。次回はWebサービスのインターフェイス記述言語WSDLを紹介する。


Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。