連載
» 2002年12月13日 00時00分 UPDATE

Webサービスのキホン(2):SOAPという封筒の内部構造

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

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

SOAPの内部構造

 SOAPは、本をただせばHTTPやXMLなどのインターネット標準技術を使うことによって、Web上の分散オブジェクトをプラットフォームの壁を越えて利用することを可能にするために開発されたプロトコルだ。本連載第1回「Webサービスの主役、SOAP誕生の背景」でも述べたが、そうした背景があるため、SOAP 1.1は、SOAPを“Simple Object Access Protocol”の略としている。しかしいまでは、SOAPはオブジェクトにアクセスするだけでなく、Webサービス間で交換されるメッセージについての汎用的なフレームワークとなった。そのためSOAP 1.2では、SOAPは何かの略ではなく「SOAP」という固有名詞として扱われている。

 さて、そのSOAPが次のような構造を持っていることはほとんどの方がご存じだろう。

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

 図1を見て分かるとおり、「SOAPメッセージ」と呼ばれるのは「SOAPエンベロープ」の部分であり、そこは「SOAPヘッダ」と「SOAP本体」の2つからなる。「SOAPエンベロープ」の前に付けられているのが「プロトコルバインディングヘッダ」で、SOAPメッセージを運ぶ下位の通信プロトコル(トランスポートプロトコルと呼ぶことにする)に関係する情報が記述される。各部分を簡単に解説しよう。

(1)プロトコルバインディングヘッダ
実装するトランスポートプロトコルに依存するヘッダで、この中にプロトコルごとに定められているヘッダ情報が記述される。これを受け取ったサーバは、続くメッセージがSOAPであることを理解してSOAPに関する処理を実行する。

(2)SOAPエンベロープ
Webサービス間で交換されるメッセージを記述する部分で、SOAPメッセージの一番外側を表す。SOAPエンベロープは、大きく分けてSOAPヘッダとSOAP本体の2つの部分に分かれる。

(3)SOAPヘッダ
封筒のあて名書きに該当する部分で、実際のメッセージのヘッダ情報が記述される。SOAPメッセージの受信者がSOAP本体に記述された情報をだれ(どのサーバ)に渡し、どのように処理するべきなのか、といった情報が記述される。従ってSOAPを実装したアプリケーションに依存する部分をこのSOAPヘッダに記述することになる。SOAPヘッダは省略可能だ。

(4)SOAP本体
封筒の中身に該当する部分で、メッセージの本文が記述される。実際に交換されるXMLデータが入る。具体的にはRPC呼び出しを行うメソッド名やその引数などの情報が記述される。SOAP本体は必須だ。

SOAPメッセージはXML形式

 ではなぜSOAPはこのような構造になったのだろうか? ある商品の見積もりを依頼するための簡単なSOAPメッセージを使って説明しよう(リスト1)。

POST /getEstimate HTTP/1.1
Host: www.utj.co.jp
Content-Type: application/soap+xml ; charset="utf-8"
Content-Length: nnnn

<?xml version="1.0" encoding="shift_jis"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <m:getEstimate xmlns:m="http://www.unitec-denki.utj.co.jp/schema/2002/">
      <m:GoodsName>もぐらたたきキーボード</m:GoodsName>
      <m:Code>k-001</m:Code>
      <m:Value>100</m:Value>
      <m:DeliveryDate>2002-09-30</m:DeliveryDate>
    </m:getEstimate>
  </soapenv:Body>
</soapenv:Envelope>
リスト1 見積もり依頼のためのSOAPメッセージ

 リスト1からすぐに分かるように、SOAPエンベロープもSOAP本体に格納されるメッセージ本文も、データ形式としてXMLが採用されている。XMLは、システムによる自動処理が容易なうえ、仕様の変更にも柔軟に対応できる、インターネット標準のデータ形式だからだ。

 しかしXML形式のメッセージでよいのなら、相手に渡したいXML文書をHTTPなどでそのまま送ればよいと思う人もいるかもしれない。例えばリスト2のような見積もり依頼のXML文書をそのまま送ることが考えられる。

<?xml version="1.0" encoding="shift_jis"?>
<getEstimate>
  <GoodsName>もぐらたたきキーボード</GoodsName>
  <Code>k-001</Code>
  <Value>100</Value>
  <DeliveryDate>2003-01-01</DeliveryDate>
</getEstimate>
リスト2 XML文書をそのままメッセージにする場合

 しかし、この方法では問題が生じる。リスト2のメッセージフォーマットは、見積依頼としての単純なリクエストには使えても、在庫照会や送金確認などの厳密性を求めるやりとりには使えない。というのも1つのサーバが複数のメッセージを同時にやりとりすると、どのメッセージがどれに対する返事なのか、といったことが分からなくなったりするからだ。ここでメッセージにセッションIDなどを埋め込む領域などを用意しておけば、個々のメッセージを区別し、関連を確認することもできるようになる。

メッセージの中身は封筒の中に入れる

 上記の問題を解決するため、SOAPメッセージは、どんなケースでも共通して使える封筒のような要素でラッピングされた構造になっている。中身の構造は異なっていても、共通に使用できるEnvelope要素でラッピングすれば汎用性が高まるわけだ。また、封筒の部分に関連情報を記述することなどもできる。リスト2をラッピングするとリスト3のようになる。

<?xml version="1.0" encoding="shift_jis"?>
<Envelope>
<Body>
    <getEstimate>
      <GoodsName>もぐらたたきキーボード</GoodsName>
      <Code>k-001</Code>
      <Value>100</Value>
      <DeliveryDate>2002-09-30</DeliveryDate>
    </getEstimate>
  </Body>
</Envelope>
リスト3 送りたいメッセージ本文を、汎用的な要素(Envelope)でラッピングする

XML名前空間で、封筒と本文を区別

 一般にSOAP対応システムにおいて、受け取ったSOAPメッセージはまずSOAP専用のプロセッサで解析されてメッセージ本文が取り出される。続いてSOAPプロセッサは、取り出したメッセージ本文をサービスの提供を行なうアプリケーションに渡して、処理できるようにする。つまり、SOAPメッセージを構成する要素・属性のうち、「汎用的な封筒の要素・属性」と「サービス固有の要素・属性」の2つがあり、それぞれは異なるプログラムによって処理されるということだ。

 1つのXML文書中に、異なるプログラムによって処理される要素・属性が混在する場合、XML名前空間を使用して要素・属性を区別する。こうして要素名・属性名の衝突を防ぐ。

 同様にSOAPメッセージも、XML名前空間を使用することによって、SOAP規格が定めた封筒の要素・属性とアプリケーション固有の要素・属性を区別できるようにしている(リスト4)。

<?xml version="1.0" encoding="shift_jis"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <m:getEstimate xmlns:m="http://www.unitec-denki.utj.co.jp/schema/2002/">
      <m:GoodsName>もぐらたたきキーボード</m:GoodsName>
      <m:Code>k-001</m:Code>
      <m:Value>100</m:Value>
      <m:DeliveryDate>2002-09-30</m:DeliveryDate>
    </m:getEstimate>
  </soapenv:Body>
</soapenv:Envelope>
リスト4 名前空間接頭辞を付与されたXMLメッセージ
http://schemas.xmlsoap.org/soap/envelope/は、SOAPの要素・属性の名前空間URI。
xmlns:m="http://www.unitec-denki.utj.co.jp/schema/2002/"は、見積もり依頼サービス固有の要素・属性の名前空間URI

封筒構造のメッセージとトランスポートプロトコルを切り離す

 リスト4を見て分かるとおり、SOAPメッセージ中には特定のトランスポートプロトコルに関する記述はない。SOAPが規定しているのは、やりとりされるデータをラッピングする部分のデータフォーマットだけであり、トランスポートプロトコルに左右されずに任意の構造のメッセージをやりとりできる。封筒の形式だけを規定し、その中に入れる書類の種類や運送方法にはこだわらないという発想だ。

 トランスポートプロトコルについての記述は、SOAPエンベロープの手前の「プロトコルバインディングヘッダ」部分に書かれる。例えば、次のように記述される。

POST /getEstimate HTTP/1.1
Host: www.utj.co.jp
Content-Type: application/soap+xml ; charset="utf-8"
Content-Length: nnnn

<?xml version="1.0" encoding="shift_jis"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <m:getEstimate xmlns:m="http://www.unitec-denki.utj.co.jp/schema/2002/">
      <m:GoodsName>もぐらたたきキーボード</m:GoodsName>
      <m:Code>k-001</m:Code>
      <m:Value>100</m:Value>
      <m:DeliveryDate>2002-09-30</m:DeliveryDate>
    </m:getEstimate>
  </soapenv:Body>
</soapenv:Envelope>
リスト5 プロトコルバインディングヘッダ(濃い文字色)と、SOAPメッセージ(薄い文字色)

 上記はHTTPを使ってSOAPメッセージを運ぶ例だが、SOAPはHTTPしか利用できないわけではない。SMTPやFTPなどのプロトコルを使用することもできる。SOAP 1.2では、HTTPバインディングを標準的なものとして推奨するものの、ほかの選択も可能であることを示すため、SMTPバインディングを使用した電子メールの例も取り上げている。

 このように、SOAPは、トランスポートプロトコルに関する部分である「プロトコルバインディングヘッダ」と、SOAPメッセージを表す「SOAPエンベロープ」とが切り離されているため、トランスポートプロトコルに依存しないメッセージ交換が可能だ。

SOAPフォルトでエラーを返す

 SOAPでは、サーバ上で何らかのエラーが発生した場合、封筒構造のSOAP本体にSOAPフォルトと呼ばれるエラー情報を格納して、呼び出し元に返すこともできる。SOAPフォルトの例を見てみよう。

HTTP/1.1 500 Internal Server Error
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn

<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>

    <soapenv:Fault>
      <faultcode>soapenv::Server</faultcode>
      <faultstring>Server Error</faultstring>
      <detail>
        <e:myfaultdetails xmlns:e="http://www.utj.co.jp/faults">
          <message>My application didn't work</message>
          <errorcode>1001</errorcode>
        </e:myfaultdetails>
      </detail>
    </soapenv:Fault>
  </soapenv:Body>
</soapenv:Envelope>
リスト6 SOAPフォルトの記述例(濃い文字色のところ)

 リスト6にあるように、SOAPフォルトはFault要素を使用して、SOAP本体に記述する。この要素はSOAP本体中に一度しか記述することができない。また、Fault要素も、Envelope要素、Header要素、Body要素と同じ名前空間に属するため、名前空間接頭辞「soapenv」を用いて修飾する。表1に示すようにFault要素にはエラーの状態や詳細情報を記述するための子要素も定義されている。SOAP 1.1とSOAP 1.2では違いがあるので比較してみよう。

SOAP 1.1 SOAP 1.2 用途・用法
faultcode Code 違反コードを記述する
faultstring Reason 人間が読めるエラー解説を記述する
faultactor Node エラー発生元のURIを記述する
Role エラー発生時点でのノードの役割を示すURIを記述する
detail Detail SOAP本体に関係するアプリケーション固有のエラー情報を記述する
表1 Fault要素の子要素

 SOAP 1.1では、Fault要素の子要素として4種類の要素が定義されていたが、SOAP 1.2では5種類の要素が定義されている。また、SOAP 1.2におけるSOAPフォルトでは、SOAPのエラーメッセージを運んでいることを認識させるため、Fault要素がBody要素の唯一の子要素でなければならないことが仕様書に明示されている。


 今回はSOAPメッセージの内部構造の概要について見てきた。SOAPがトランスポートプロトコルに依存せずにデータを記述する仕組みについて理解していただけただろう。次回は、SOAPによるリモートプロシジャコールの表現方法などについて解説していく。


Copyright© 2014 ITmedia, Inc. All Rights Reserved.

TechTargetジャパン

@IT eBookシリーズ、創刊

ホワイトペーパー(TechTargetジャパン)

注目のテーマ

Focus

- PR -

転職/派遣情報を探す

【転職サーチ】SIer/Web企業/新規事業 スマホ開発で、あなたのキャリアを生かす

「派遣・フリーで働くメリット」とは? 活躍する派遣エンジニアの本音

RSSについて

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

メールマガジン登録

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