soap-errorsnetworkingtroubleshooting

SOAP API の接続タイムアウトと Connection Refused の対処法

SOAPless Team8 min read

SOAP API の連携開発で突然 「Connection Timed Out」「Connection Refused」 というエラーが発生すると、原因の特定に苦労します。ネットワーク層の問題なのか、SOAP サービス側の問題なのか、あるいはクライアントの設定ミスなのか。この記事では、これらのエラーの原因をレイヤーごとに分析し、体系的な対処法を解説します。

Connection Refused と Connection Timed Out の違い

まず、この 2 つのエラーは根本的に異なります。

Connection Refused(接続拒否): サーバーに到達できたが、指定ポートでサービスが待ち受けていない。TCP レベルで即座に RST パケットが返される。

Connection Timed Out(接続タイムアウト): サーバーに到達できず、TCP 接続の確立がタイムアウトした。ファイアウォールでパケットが遮断されている可能性が高い。

# Connection Refused の例
$ curl https://example.com:8443/service?wsdl
curl: (7) Failed to connect to example.com port 8443: Connection refused

# Connection Timed Out の例
$ curl --connect-timeout 10 https://example.com/service?wsdl
curl: (28) Connection timed out after 10001 milliseconds

原因 1: ファイアウォールとネットワーク制限

企業の SOAP サービスは多くの場合、IP ホワイトリストやファイアウォールルールで保護されています。自社の IP アドレスがアクセス許可リストに含まれていない場合、Connection Timed Out になります。

確認方法:

# サーバーのポートに到達できるか確認
nc -zv example.com 443 -w 5
# 成功例: Connection to example.com 443 port [tcp/https] succeeded!
# 失敗例: nc: connectx to example.com port 443 (tcp) failed: Operation timed out

# 自分のグローバル IP を確認
curl https://ifconfig.me

# traceroute でパケットの経路を確認
traceroute example.com

対処法: サービスプロバイダーにグローバル IP アドレスのホワイトリスト登録を依頼してください。クラウド環境の場合、NAT ゲートウェイや Elastic IP の固定 IP を使用する必要があります。

原因 2: プロキシ設定の問題

企業ネットワークではインターネットアクセスにプロキシサーバーを経由することが一般的です。SOAP クライアントがプロキシを経由していない場合、外部のサービスに到達できません。

// Node.js: node-soap でプロキシを設定
const soap = require('soap');
const HttpsProxyAgent = require('https-proxy-agent');

const agent = new HttpsProxyAgent('http://proxy.corp.example.com:8080');

const client = await soap.createClientAsync(wsdlUrl, {
  request: require('axios').create({
    httpsAgent: agent,
    proxy: false // axios 独自のプロキシ設定を無効化
  })
});
# Python: zeep でプロキシを設定
from zeep import Client
from zeep.transports import Transport
from requests import Session

session = Session()
session.proxies = {
    'http': 'http://proxy.corp.example.com:8080',
    'https': 'http://proxy.corp.example.com:8080'
}

transport = Transport(session=session)
client = Client(wsdl_url, transport=transport)
# curl でプロキシ経由の確認
curl -x http://proxy.corp.example.com:8080 https://example.com/service?wsdl

対処法: ネットワーク管理者にプロキシサーバーのアドレスを確認し、SOAP クライアントに正しく設定してください。

原因 3: SSL/TLS の問題

SOAP サービスが古い TLS バージョン(TLS 1.0/1.1)のみをサポートしている場合や、自己署名証明書を使用している場合、接続に失敗します。

# サーバーの TLS バージョンを確認
openssl s_client -connect example.com:443 -tls1_2

# 証明書の詳細を確認
openssl s_client -connect example.com:443 -showcerts 2>/dev/null | \
  openssl x509 -noout -dates -subject
// Node.js: 自己署名証明書を一時的に許可(開発環境のみ)
const https = require('https');
const agent = new https.Agent({
  rejectUnauthorized: false  // 本番環境では絶対に使わない
});

const client = await soap.createClientAsync(wsdlUrl, {
  request: require('axios').create({ httpsAgent: agent })
});

対処法: サーバーが古い TLS のみ対応の場合はプロバイダーに更新を要請してください。自己署名証明書の場合は、その CA 証明書をクライアントの信頼ストアに追加してください。

原因 4: サービスのエンドポイント URL の間違い

WSDL に記載されたエンドポイント URL と実際のサービス URL が異なるケースがあります。特に、WSDL が内部ネットワーク用の URL(http://localhost:8080/service など)を含んでいる場合に問題が発生します。

<!-- WSDL 内のサービス定義を確認 -->
<wsdl:service name="UserService">
  <wsdl:port name="UserPort" binding="tns:UserBinding">
    <!-- この URL が正しいか確認 -->
    <soap:address location="http://internal-server:8080/UserService"/>
  </wsdl:port>
</wsdl:service>

対処法: WSDL を取得した URL とエンドポイントが一致しているか確認してください。多くの SOAP クライアントライブラリでは、エンドポイント URL を上書きできます。

// node-soap: エンドポイントを上書き
client.setEndpoint('https://actual-server.example.com/UserService');

原因 5: タイムアウト値の設定不足

SOAP サービスは処理に時間がかかることがあります。特に、大量のデータを返すオペレーションや、バックエンドで複数のシステムを呼び出す処理では、デフォルトのタイムアウト値(多くの場合 30 秒)を超えることがあります。

// Node.js: タイムアウト値の設定
const client = await soap.createClientAsync(wsdlUrl, {
  request: require('axios').create({
    timeout: 120000  // 120 秒
  })
});
# Python: zeep でタイムアウトを設定
from zeep import Client
from zeep.transports import Transport

transport = Transport(timeout=120, operation_timeout=120)
client = Client(wsdl_url, transport=transport)
// Java: JAX-WS でタイムアウトを設定
BindingProvider bp = (BindingProvider) port;
bp.getRequestContext().put("com.sun.xml.ws.connect.timeout", 120000);
bp.getRequestContext().put("com.sun.xml.ws.request.timeout", 120000);

体系的なデバッグ手順

接続エラーに遭遇したら、レイヤーの下から順に確認していくのが効率的です。

  1. DNS 解決: nslookup または dig でホスト名が正しく解決されるか確認する。
  2. TCP 接続: nc -zv でポートに到達できるか確認する。
  3. TLS ハンドシェイク: openssl s_client で証明書と TLS バージョンを確認する。
  4. HTTP レイヤー: curl -v で HTTP リクエストとレスポンスの詳細を確認する。
  5. SOAP レイヤー: 上記がすべて成功したら、SOAP エンベロープの内容を確認する。
# 上記をまとめて確認するワンライナー
curl -v --connect-timeout 10 -H "Content-Type: text/xml" \
  "https://example.com/service?wsdl" 2>&1 | head -30

ネットワーク問題を回避する構成

SOAP サービスとの接続で頻繁にネットワーク問題が発生する場合、クライアントとサービスの間にプロキシ層を設けることで安定性を向上できます。SOAPless は SOAP サービスへの接続を一元管理し、リトライ処理やタイムアウト制御を自動で行います。クライアント側は SOAPless の REST エンドポイントに JSON を送るだけなので、ネットワーク設定の複雑さから解放されます。WSDL の URL を入力すれば約 30 秒で利用を開始でき、SOAP 特有の接続問題の多くを SOAPless 側で吸収できます。