soap-errorstroubleshootingweb-services

SOAP VersionMismatch エラー: SOAP 1.1 と 1.2 のエンベロープ競合を解決する方法

SOAPless Team7 min read

正しく構築した SOAP リクエストを送信したにもかかわらず、以下のようなレスポンスが返ってくることがあります。

<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
  <env:Body>
    <env:Fault>
      <env:Code>
        <env:Value>env:VersionMismatch</env:Value>
      </env:Code>
      <env:Reason>
        <env:Text xml:lang="en">
          Wrong SOAP version used. Expected SOAP 1.1, received SOAP 1.2.
        </env:Text>
      </env:Reason>
    </env:Fault>
  </env:Body>
</env:Envelope>

VersionMismatch fault は明確なエラーです。サービスがサポートしていないバージョンの SOAP エンベロープを受信したことを意味します。SOAP 1.2 を SOAP 1.1 のエンドポイントに送信した、またはその逆が原因です。

SOAP の 2 つのバージョン

SOAP 1.1 (2000 年リリース) と SOAP 1.2 (2003 年リリース) はワイヤレベルで互換性がありません。VersionMismatch fault を引き起こす主な違いは 3 つあります。

エンベロープ namespace

SOAP プロセッサがバージョンを判定する最も重要な識別子です。

SOAP 1.1:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <!-- 操作内容 -->
  </soap:Body>
</soap:Envelope>

SOAP 1.2:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Body>
    <!-- 操作内容 -->
  </soap:Body>
</soap:Envelope>

SOAP 1.1 エンドポイントが http://www.w3.org/2003/05/soap-envelope を検出すると、リクエストを即座に拒否します。

Content-Type ヘッダー

HTTP の Content-Type ヘッダーもバージョンによって異なり、多くのサーバーは XML 本文を解析する前にこのヘッダーを検証します。

バージョンContent-Typeアクションの指定方法
SOAP 1.1text/xml; charset=utf-8個別の SOAPAction HTTP ヘッダー
SOAP 1.2application/soap+xml; charset=utf-8Content-Type 内の action パラメータ

SOAPAction の違い

SOAP 1.1 では、アクションは専用の HTTP ヘッダーで送信します。

POST /service.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://example.com/GetOrder"

SOAP 1.2 では、アクションは Content-Type ヘッダーに埋め込まれます。

POST /service.svc HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8; action="http://example.com/GetOrder"

WSDL からバージョンを特定する方法

修正前に、サービスが期待するバージョンを確認する必要があります。WSDL のバインディング定義で明確に判別できます。

SOAP 1.1 の場合

<wsdl:binding name="OrderServiceSoap" type="tns:OrderServiceSoap">
  <soap:binding transport="http://schemas.xmlsoap.org/soap/http"
                style="document" />
  <!-- namespace が http://schemas.xmlsoap.org/wsdl/soap/ → SOAP 1.1 -->
</wsdl:binding>

SOAP 1.2 の場合

<wsdl:binding name="OrderServiceSoap12" type="tns:OrderServiceSoap">
  <soap12:binding transport="http://schemas.xmlsoap.org/soap/http"
                  style="document" />
  <!-- namespace が http://schemas.xmlsoap.org/wsdl/soap12/ → SOAP 1.2 -->
</wsdl:binding>

WSDL が両方のバインディングを定義している場合は、サービスは両バージョンに対応しています。バージョンに対応する正しいエンドポイント URL を使用してください。

各言語での修正方法

curl でのテスト

SOAP 1.1:

curl -X POST https://api.example.com/service.asmx \
  -H "Content-Type: text/xml; charset=utf-8" \
  -H 'SOAPAction: "http://example.com/GetOrder"' \
  -d '<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetOrder xmlns="http://example.com/">
      <orderId>12345</orderId>
    </GetOrder>
  </soap:Body>
</soap:Envelope>'

SOAP 1.2:

curl -X POST https://api.example.com/service.svc \
  -H 'Content-Type: application/soap+xml; charset=utf-8; action="http://example.com/GetOrder"' \
  -d '<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Body>
    <GetOrder xmlns="http://example.com/">
      <orderId>12345</orderId>
    </GetOrder>
  </soap:Body>
</soap:Envelope>'

Python (zeep)

from zeep import Client

# zeep は WSDL バインディングからバージョンを自動検出します
client = Client("https://api.example.com/service?wsdl")

# 両バージョンのバインディングがある場合は明示的に選択
client_1_2 = Client(
    "https://api.example.com/service?wsdl",
    service_name="OrderService",
    port_name="OrderServiceSoap12"
)

Java (JAX-WS)

OrderService service = new OrderService();
// SOAP 1.2 のポートを使用
OrderServiceSoap port = service.getOrderServiceSoap12();

Node.js (soap npm パッケージ)

const soap = require("soap");

// SOAP 1.2 を強制
const options = {
  forceSoap12Headers: true,
};

soap.createClient(wsdlUrl, options, (err, client) => {
  client.GetOrder({ orderId: "12345" }, (err, result) => {
    console.log(result);
  });
});

.NET (WCF)

<!-- SOAP 1.1 の場合は basicHttpBinding -->
<endpoint binding="basicHttpBinding" contract="IOrderService" />

<!-- SOAP 1.2 の場合は wsHttpBinding -->
<endpoint binding="wsHttpBinding" contract="IOrderService" />

明示的にバージョンを制御する場合:

<customBinding>
  <binding name="Soap12Binding">
    <textMessageEncoding messageVersion="Soap12" />
    <httpTransport />
  </binding>
</customBinding>

Fault 構造の違い

エラーハンドリングコードに影響するため、Fault 構造の違いも把握しておきましょう。

SOAP 1.1 Fault:

<soap:Fault>
  <faultcode>soap:VersionMismatch</faultcode>
  <faultstring>Version mismatch</faultstring>
  <detail>Expected SOAP 1.1</detail>
</soap:Fault>

SOAP 1.2 Fault:

<env:Fault>
  <env:Code>
    <env:Value>env:VersionMismatch</env:Value>
    <env:Subcode>
      <env:Value>rpc:BadArguments</env:Value>
    </env:Subcode>
  </env:Code>
  <env:Reason>
    <env:Text xml:lang="en">Version mismatch</env:Text>
  </env:Reason>
</env:Fault>

SOAP 1.2 ではフラットな faultcode 文字列の代わりに、構造化された Code/Subcode 階層を使用します。エラーハンドリングコードが faultcode をパースしている場合、SOAP 1.2 のレスポンスでは詳細情報を見逃してしまいます。

診断手順

  1. 生の HTTP リクエストをキャプチャする (Fiddler、mitmproxy、Wireshark などを使用) — Content-Type ヘッダーとエンベロープ namespace を確認
  2. WSDL をダウンロードして確認するsoap:bindingsoap12:binding かでバージョンを特定
  3. namespace と Content-Type の両方を修正する — 片方だけの修正では依然としてエラーが発生する
  4. デュアルバインディング WSDL を確認する — 両バージョンが公開されている場合、送信バージョンに対応するエンドポイント URL を使用していることを確認

SOAPless による解決

SOAP のバージョン不一致は、特にサーバー設定を制御できないサードパーティサービスを利用する場合に頻出する問題です。SOAPless はこの摩擦を完全に排除します。

SOAPless に WSDL を登録すると、プラットフォームが上流サービスの SOAP 1.1/1.2 を自動検出します。WSDL のバインディング namespace を読み取り、正しいエンベロープ namespace、Content-Type ヘッダー、アクション形式でリクエストを構築します。アプリケーションからは単純な REST JSON 呼び出しを行うだけです。XML 構築、バージョン固有のヘッダー、Content-Type の推測は一切不要です。

また、登録したサービスごとに OpenAPI 仕様を自動生成するため、ダッシュボードから直接操作を確認・テストでき、コードを書く前に動作を確認できます。