首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 呼叫 .NET WebService 完整教學:SOAP Client 實作與常見問題排解

     編輯:PHP 相關知識

前言

企業級系統整合常需 PHP 呼叫 .NET (ASMX/WCF) 發布的 SOAP WebService。PHP 內建 SoapClient 提供完整支援,但編碼、命名空間、參數結構等細節極易踩坑。

環境準備

# 安裝擴展
apt-get install php-soap      # Debian/Ubuntu
yum install php-soap          # CentOS/RHEL
# php.ini 確認
extension=soap

基本呼叫流程

<?php
// 1. 實例化(WSDL 模式)
$wsdl = 'https://example.com/Service.asmx?WSDL';
$client = new SoapClient($wsdl, [
    'trace'            => 1,              // 除錯:保留最後請求/回應
    'exceptions'       => true,           // 拋出 SoapFault 異常
    'soap_version'     => SOAP_1_1,       // 或 SOAP_1_2
    'encoding'         => 'UTF-8',        // 請求編碼
    'cache_wsdl'       => WSDL_CACHE_MEMORY, // 開發建議關閉快取
    'connection_timeout' => 10,
    'stream_context'   => stream_context_create([
        'ssl' => [
            'verify_peer' => false,       // 測試環境忽略 SSL 驗證
            'verify_peer_name' => false,
        ]
    ]),
]);

// 2. 檢視可用函數與型別(除錯用)
// var_dump($client->__getFunctions());
// var_dump($client->__getTypes());

// 3. 呼叫方法
try {
    $params = [
        'param1' => '01',
        'param2' => '02',
    ];
    // 關鍵:參數需包裝成陣列的陣列,對應 WSDL 定義的 message parts
    $response = $client->__soapCall('GetArticle', [$params]);
    // 或直接呼叫(若方法名符合 PHP 命名規則)
    // $response = $client->GetArticle($params);

    // 4. 處理回應
    if (is_soap_fault($response)) {
        throw new \SoapFault($response->faultcode, $response->faultstring);
    }
    // .NET 回傳通常包裝在 GetArticleResult 屬性
    $data = $response->GetArticleResult ?? $response;
    var_dump($data);

} catch (SoapFault $e) {
    error_log("SOAP Fault: [{$e->faultcode}] {$e->faultstring}");
    // 除錯:查看原始 XML
    if (isset($client)) {
        error_log("Request:\n" . $client->__getLastRequest());
        error_log("Response:\n" . $client->__getLastResponse());
    }
}
?>

關鍵坑點與解決方案

1. 參數結構:陣列的陣列

.NET WSDL 定義的 message 通常有多個 part,PHP 需傳遞 [['part1' => val1, 'part2' => val2]](外層陣列對應參數列表,內層對應各 part)。單一 part 也要用雙層:[['xml' => $xmlString]]。

2. 命名空間與型別對應

複雜型別(如 .NET 的 DataSet、自定義類)會對應到 PHP 的 stdClass 或陣列。可使用 classmap 選項映射到自定義類:

$client = new SoapClient($wsdl, [
    'classmap' => [
        'UserInfo' => \App\Dto\UserInfo::class,
        'OrderDetail' => \App\Dto\OrderDetail::class,
    ],
]);

3. 編碼問題

  • WSDL 聲明 encoding="UTF-8",PHP 端設 'encoding' => 'UTF-8'。
  • 若 .NET 端預期 utf-8 但實際發送 gb2312,需在 stream_context 設 'http' => ['header' => 'Content-Type: text/xml; charset=utf-8']。
  • 回應中文亂碼:確認 HTTP Header Content-Type: text/xml; charset=utf-8,必要時 mb_convert_encoding($xml, 'UTF-8', 'GB2312')。

4. SSL/TLS 憑證驗證

// 生產環境必須驗證
'stream_context' => stream_context_create([
    'ssl' => [
        'verify_peer' => true,
        'verify_peer_name' => true,
        'cafile' => '/etc/ssl/certs/ca-certificates.crt', // 系統 CA 憑證包
        'ciphers' => 'HIGH:!aNULL:!MD5:!3DES',
    ]
])

5. Session/Cookie 維持(如需登入態)

$client = new SoapClient($wsdl, [
    'keep_alive' => true,
    'cookies' => true, // 自動處理 Set-Cookie
]);
// 登入
$client->Login(['username' => 'u', 'password' => 'p']);
// 後續呼叫自動攜帶 Cookie
$client->GetData([]);

6. 非 WSDL 模式(手動指定端點)

$client = new SoapClient(null, [
    'location' => 'https://example.com/Service.asmx',
    'uri'      => 'https://tempuri.org/', // 命名空間
    'trace'    => 1,
]);
$client->__soapCall('GetArticle', [['param1' => '01']]);

除錯神技:攔截原始 XML

// 開啟 trace 後
echo "REQUEST:\n" . $client->__getLastRequest() . "\n";
echo "RESPONSE:\n" . $client->__getLastResponse() . "\n";
echo "REQUEST HEADERS:\n" . $client->__getLastRequestHeaders() . "\n";
echo "RESPONSE HEADERS:\n" . $client->__getLastResponseHeaders() . "\n";

將輸出存檔,用 SoapUI/Postman 對比驗證。

效能優化建議

  • 啟用 WSDL 快取:'cache_wsdl' => WSDL_CACHE_DISK,生產環境設定 ini_set('soap.wsdl_cache_ttl', 86400)。
  • 重用 SoapClient 實例(單例模式),避免重複解析 WSDL。
  • 大量資料傳輸考慮 MTOM(Message Transmission Optimization Mechanism),需 .NET 端同步配置。

總結

PHP SoapClient 功能強大但細節多。掌握「參數雙層陣列、命名空間映射、編碼統一、SSL 驗證、原始 XML 除錯」五大核心,即可解決 90% 的 .NET WebService 整合問題。建議封裝統一的 SoapServiceClient 基類,集中處理異常、日誌、重試、快取等橫切關注點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved