熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> PHP編程 >> 正文

PHP5中使用Web服務訪問J2EE應用程序(2)

2013-11-15 12:21:03  來源: PHP編程 

  我們成功地與 Weather 服務取得了聯系並顯示了結果但是如果出現錯誤得不到預期的結果該怎麼辦?ext/soap 可以顯示客戶機與服務器之間交換的 SOAP 消息能夠幫助我們確定問題所在
  
  只有使用 trace 選項創建 SoapClient 時才要使用跟蹤功能我們在 options 數組參數中設置 trace 選項將該參數傳遞給 SoapClient 構造函數我們將構造函數的使用改為
  
  $soapClient = new SoapClient(//localhost:/
  ItsoWebServiceRouterWeb/wsdl/itso/session/WeatherForecastEJBwsdl
  array(trace => ));
  
  並在調用 goForecast 之後調用 trace 方法
  
  echo Request :<br> htmlspecialchars($soapClient>__getLastRequest()) <br>;
  echo Response :<br> htmlspecialchars($soapClient>__getLastResponse()) <br>;
  
  一定要使用 htmlspecialchars 內置函數對 trace 輸出進行編碼因為它將 SOAP xml 分界符轉換成特殊字符如 <這樣可以避免浏覽器將其解釋成標記
  
  下面是某個請求的 trace 輸出
  
  <?xml version= encoding=UTF?>
  <SOAPENV:Envelope xmlns:SOAPENV=
  xmlns:ns=
  <SOAPENV:Body>
  <ns:getForecast>
  <ns:startDate>T::</ns:startDate>
  <ns:days></ns:days>
  </ns:getForecast>
  </SOAPENV:Body>
  </SOAPENV:Envelope>
  
  對應的應答是
  
  <?xml version= encoding=UTF?>
  <soapenv:Envelope xmlns:soapenv=
  xmlns:soapenc=
  xmlns:xsd=
  xmlns:xsi=instance
  <soapenv:Body>
  <getForecastResponse xmlns=
  <getForecastReturn xmlns:ns=
  <ns:condition>sunny</ns:condition>
  <ns:date>T::Z</ns:date>
  <ns:windDirection>W</ns:windDirection>
  <ns:windSpeed></ns:windSpeed>
  <ns:temperatureCelsius></ns:temperatureCelsius>
  <ns:dbflag></ns:dbflag>
  </getForecastReturn>
  </getForecastResponse>
  </soapenv:Body>
  </soapenv:Envelope>
  
  如果在開啟跟蹤功能的情況下運行客戶機來收集這些輸出那麼需要將 days 參數設置為 只有這樣做SOAP 應答才會輸出較少的行但是我們遇到了沒有預料到的行為我們本來期望 getForecastResponse 和以前一樣是一個 Weather 對象數組但是它應該只有一個元素而不是 個元素然而它被轉換成了一個簡單的 Weather 對象我們必須根據這種行為進行編碼就像您在最終的示例 PHP 客戶機代碼中看到的那樣這與 Java 客戶機的行為有所不同在客戶機行為中getForecast 總是返回 Weather 對象數組無論服務器響應中有多少個 Weather 對象SoapClient::_getTypes() 輸出並沒有為我們理解這種差異提供足夠的細節因此我們要求助於 WSDL 文檔來了解完整的接口規范
  
  解釋 WSDL
  
  我們已經成功地調用了 Weather 服務但是還沒有看過它的 WSDL 文檔WSDL 中的細節要比 SoapClient 公開的多我們如何知道應該在 startDate 參數中放什麼呢?我們應該期望從返回的數據中實際得到什麼?要回答這些問題必須更深入地分析 WSDL
  
  可以從下載部分下載 Weather Forecast 應用程序的 WSDL如果使用不同的 Web 服務只需要在浏覽器中打開相應的 WSDL 文檔即可
  
  getForecast 操作的 WSDL 是
  
  <wsdl:operation name=getForecast
  <wsdl:input message=intf:getForecastRequest name=getForecastRequest/>
  <wsdl:output message=intf:getForecastResponse name=getForecastResponse/>
  </wsdl:operation>
  
  其中的 getForecastRequest 消息被定義為
  
  <wsdl:message name=getForecastRequest
  <wsdl:part element=intf:getForecast name=parameters/>
  </wsdl:message>
  
  而 getForecast 結構被定義為
  
  <element name=getForecast
  <complexType>
  <sequence>
  <element name=startDate nillable=true type=xsd:dateTime/>
  <element name=days type=xsd:int/>
  </sequence>
  </complexType>
  </element>
  
  於是我們知道該函數需要兩個參數xsd:dateTime 類型的 startDate 和整數類型的 days這與我們所了解的 SoapClient::_getTypes 函數完全匹配但是現在我們還知道 startDate 可以為空(nillable)毫無疑問如果我們簡化輸入參數那麼該函數將如下所示
  
  $forecastResponse = $soapClient>getForecast(array(startDate=>Null days=>));
  
  如果明確指定今天的日期結果會與所指定的完全一致
  
  如果希望制定其他起始日期怎麼辦呢?XML Schema將 dateTime 定義成一種基本類型按照 ISO 標准格式化比如T::假設希望了解三天之後的天氣預報可以使用內置函數 strtotime(+ days) 獲得需要的日期該函數與 time() 函數相同都返回標准 UNIX 格式的日期時間即表示從公元紀年開始到現在的秒數的一個整數我們知道 XML Schema 要求日期采用具有字符串字段的 ISO 格式進行編碼於是在示例客戶機中編寫了 timeToIso 函數將整數日期轉換成 SOAP 編碼定義的格式但我們吃驚地發現其實並不需要這樣做ext/soap 非常聰明地將整數日期轉化成了需要的字符串字段格式無論傳遞的是整數還是預格式化的字符串都沒有關系最終傳送的 SOAP 消息都是一樣的
  
  響應中的日期又如何呢?在回程中ext/soap 從 SOAP 響應獲得了 dateTime 字段但是沒有做任何格式轉換我們希望它返回一個整數以表示從公元紀年到現在的秒數但實際上得到的是按照 ISO 格式化的字符串於是我們使用 strtotime 函數將其轉化成整數然後使用 strftime 格式化該整數以便於表示
  
  Weather Service 按日期提供預報但它忽略了 dateTime 編碼中的時間成分所以我們沒有考慮這方面的調整如果從運行在不同時區內的服務中請求天氣預報那麼可能必須這樣做如果希望進一步了解時區轉換請參閱參考資料中給出的描述 ISO 標准的文章
  
  現在再回到響應格式上來上一節中曾經提到 getForecast 返回數據的不一致性WSDL 描述告訴我們 getForecast 返回一個 getForecastResponse 對象getForecastResponse 可以包含無限多個稱為 Weather 的復雜類型的列表
  
  <element name=getForecastResponse
  <complexType>
  <sequence>
  <element maxOccurs=unbounded name=getForecastReturn type=tns:Weather/>
  </sequence>
  </complexType>
  </element>
  
  <complexType name=Weather
  <sequence>
  <element name=condition nillable=true type=xsd:string/>
  <element name=date nillable=true type=xsd:dateTime/>
  <element name=windDirection nillable=true type=xsd:string/>
  <element name=windSpeed type=xsd:int/>
  <element name=temperatureCelsius type=xsd:int/>
  <element name=dbflag type=xsd:boolean/>
  </sequence>
  </complexType>
  
  WSDL 不允許出現單元素數組這種特例不幸的是當響應只包含一個 Weather 對象時ext/soap 沒有考慮 WSDL 中應用於 getForecastResponse 的 <sequence> 標簽因為這種行為在客戶機代碼中造成了不必要的復雜性
  
  最後WSDL 文檔還告訴 SOAP 客戶機可以從網絡中的哪個地方找到該服務
  
  <wsdl:service name=WeatherForecastEJBService
  <wsdl:port binding=intf:WeatherForecastEJBSoapBinding
  name=WeatherForecastEJB
  <wsdlsoap:address location=
  //localhost:/ItsoWebServiceRouterWeb/services/WeatherForecastEJB/>
  </wsdl:port>
  </wsdl:service>
  
  處理 SOAP 錯誤
  
  如果運行客戶機時出現錯誤怎麼辦?與其他語言(如 Java)一樣PHP 新增加了一種異常機制ext/soap 使用這種新的機制以 SoapFault 對象的形式返回錯誤比方說可以用下面這種形式將代碼包裝起來
  
  try {
   some SOAP operation
  } catch (SoapFault $soapFault) {
  echo $soapFault;
  }
  
  注意與 Java 有所不同PHP 語言的 try catch 塊不能包含 finally
From:http://tw.wingwit.com/Article/program/PHP/201311/20772.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.