正しく構築した 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.1 | text/xml; charset=utf-8 | 個別の SOAPAction HTTP ヘッダー |
| SOAP 1.2 | application/soap+xml; charset=utf-8 | Content-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 のレスポンスでは詳細情報を見逃してしまいます。
診断手順
- 生の HTTP リクエストをキャプチャする (Fiddler、mitmproxy、Wireshark などを使用) — Content-Type ヘッダーとエンベロープ namespace を確認
- WSDL をダウンロードして確認する —
soap:bindingかsoap12:bindingかでバージョンを特定 - namespace と Content-Type の両方を修正する — 片方だけの修正では依然としてエラーが発生する
- デュアルバインディング WSDL を確認する — 両バージョンが公開されている場合、送信バージョンに対応するエンドポイント URL を使用していることを確認
SOAPless による解決
SOAP のバージョン不一致は、特にサーバー設定を制御できないサードパーティサービスを利用する場合に頻出する問題です。SOAPless はこの摩擦を完全に排除します。
SOAPless に WSDL を登録すると、プラットフォームが上流サービスの SOAP 1.1/1.2 を自動検出します。WSDL のバインディング namespace を読み取り、正しいエンベロープ namespace、Content-Type ヘッダー、アクション形式でリクエストを構築します。アプリケーションからは単純な REST JSON 呼び出しを行うだけです。XML 構築、バージョン固有のヘッダー、Content-Type の推測は一切不要です。
また、登録したサービスごとに OpenAPI 仕様を自動生成するため、ダッシュボードから直接操作を確認・テストでき、コードを書く前に動作を確認できます。