<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            12.8.  SOAP 網絡服務故障排除

            是的,SOAP 網絡服務的世界中也不總是歡樂和陽光。有時候也會有故障。

            正如你在本章中看到的,SOAP 牽扯了很多層面。SOAP 向 HTTP 服務器發送 XML 文檔并接收返回的 XML 文檔時需要用到 HTTP 層。這樣一來,你在 第 11 章 HTTP Web 服務 學到的調試技術在這里都有了用武之地。你可以 import httplib 并設置 httplib.HTTPConnection.debuglevel = 1 來查看潛在的 HTTP 傳輸。

            在 HTTP 層之上,還有幾個可能發生問題的地方。SOAPpy 隱藏 SOAP 語法的本領令你驚嘆不已,但也意味著在發生問題時更難確定問題所在。

            下面的這些例子是我在使用 SOAP 網絡服務時犯過的一些常見錯誤以及所產生的錯誤信息。

            例 12.15. 以錯誤的設置調用 Proxy 方法

            >>> from SOAPpy import SOAPProxy
            >>> url = 'http://services.xmethods.net:80/soap/servlet/rpcrouter'
            >>> server = SOAPProxy(url)                                        1
            >>> server.getTemp('27502')                                        2
            <Fault SOAP-ENV:Server.BadTargetObjectURI:
            Unable to determine object id from call: is the method element namespaced?>
            Traceback (most recent call last):
              File "<stdin>", line 1, in ?
              File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 453, in __call__
                return self.__r_call(*args, **kw)
              File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 475, in __r_call
                self.__hd, self.__ma)
              File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 389, in __call
                raise p
            SOAPpy.Types.faultType: <Fault SOAP-ENV:Server.BadTargetObjectURI:
            Unable to determine object id from call: is the method element namespaced?>
            
            1 你看出錯誤了嗎?你手工地創建了一個 SOAPProxy,你正確地指定了服務 URL,但是你沒有指定命名空間。由于多個服務可能被路由到相同的服務 URL,命名空間是確定你所調用的服務和方法的重要內容。
            2 服務器返回的是一個 SOAP 錯誤 (Fault),SOAPpy 把它轉換為 Python 異常 SOAPpy.Types.faultType。從任何 SOAP 服務器返回的錯誤都是 SOAP 錯誤,因此你可以輕易地捕獲這個異常。就此處而言,我們能從 SOAP 錯誤信息中看出端倪:由于源 SOAPProxy 對象沒有設置服務命名空間,因此方法元素也就沒有了命名空間。

            錯誤配置 SOAP 服務的基本元素是 WSDL 著眼解決的問題。WSDL 文件包含服務 URL 和命名空間,所以你應該不會在這里犯錯。但是,還有其他可能出錯的地方。

            例 12.16. 以錯誤參數調用方法

            >>> wsdlFile = 'http://www.xmethods.net/sd/2001/TemperatureService.wsdl'
            >>> server = WSDL.Proxy(wsdlFile)
            >>> temperature = server.getTemp(27502)                                1
            <Fault SOAP-ENV:Server: Exception while handling service request:
            services.temperature.TempService.getTemp(int) -- no signature match>   2
            Traceback (most recent call last):
              File "<stdin>", line 1, in ?
              File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 453, in __call__
                return self.__r_call(*args, **kw)
              File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 475, in __r_call
                self.__hd, self.__ma)
              File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 389, in __call
                raise p
            SOAPpy.Types.faultType: <Fault SOAP-ENV:Server: Exception while handling service request:
            services.temperature.TempService.getTemp(int) -- no signature match>
            
            1 你看出錯誤了嗎?這是一個不易察覺的錯誤:你在使用整數而不是字符串來調用 server.getTemp 。自省 WSDL 文件不難發現,getTemp() 這個 SOAP 函數接受一個參數 zipcode,這是一個字符串參數。WSDL.Proxy 會為你強制轉換數據類型;你需要根據服務器需要的數據類型傳遞數據。
            2 又是這樣,服務器傳回一個 SOAP 錯誤,你能從 SOAP 錯誤信息中看出端倪:你在使用整數類型的參數調用 getTemp 函數,但卻沒有一個以此命名的函數接收整數參數。理論上講,SOAP 允許你重載 (overload) 函數,也就是可以在同一個 SOAP 服務中存在同名函數,并且參數個數也相同,但是參數的數據類型不同。這就是數據類型必須匹配的原因,也說明了為什么 WSDL.Proxy 不強制地為你改變數據類型。如果真的強制改變了數據類型,發生這樣的錯誤時,調用的可能是另外一個不相干的函數。看來產生這樣的錯誤是件幸運的事。對于數據類型多加注意會讓事情簡單很多,一旦搞錯了數據類型便立刻會發生錯誤。

            Python 所期待的返回值個數與遠程函數的實際返回值個數不同是另一種可能的錯誤。

            例 12.17. 調用時方法所期待的返回值個數錯誤

            >>> wsdlFile = 'http://www.xmethods.net/sd/2001/TemperatureService.wsdl'
            >>> server = WSDL.Proxy(wsdlFile)
            >>> (city, temperature) = server.getTemp(27502)  1
            Traceback (most recent call last):
              File "<stdin>", line 1, in ?
            TypeError: unpack non-sequence
            
            1 你看出錯誤了嗎?server.getTemp 只返回一個浮點值,但你寫的代碼卻期待著獲得兩個值,并把它們賦值給不同的兩個變量。注意這不是一個 SOAP 錯誤。就遠程服務器而言沒有發生任何錯誤。錯誤發生在完成 SOAP 交割之后WSDL.Proxy 返回一個浮點數,你本地的 Python 解釋器試圖將這個浮點數分成兩個變量。由于函數只返回了一個值,你在試圖分割它時所獲得的是一個 Python 異常,而不是 SOAP 錯誤。

            那么 Google 網絡服務方面又如何呢?我曾經犯過的最常見的錯誤是忘記正確設置應用許可證。

            例 12.18. 調用方法返回一個應用特定的錯誤

            >>> from SOAPpy import WSDL
            >>> server = WSDL.Proxy(r'/path/to/local/GoogleSearch.wsdl')
            >>> results = server.doGoogleSearch('foo', 'mark', 0, 10, False, "", 1
            ...     False, "", "utf-8", "utf-8")
            <Fault SOAP-ENV:Server:                                              2
             Exception from service object: Invalid authorization key: foo:
             <SOAPpy.Types.structType detail at 14164616>:
             {'stackTrace':
              'com.google.soap.search.GoogleSearchFault: Invalid authorization key: foo
               at com.google.soap.search.QueryLimits.lookUpAndLoadFromINSIfNeedBe(
                 QueryLimits.java:220)
               at com.google.soap.search.QueryLimits.validateKey(QueryLimits.java:127)
               at com.google.soap.search.GoogleSearchService.doPublicMethodChecks(
                 GoogleSearchService.java:825)
               at com.google.soap.search.GoogleSearchService.doGoogleSearch(
                 GoogleSearchService.java:121)
               at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source)
               at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
               at java.lang.reflect.Method.invoke(Unknown Source)
               at org.apache.soap.server.RPCRouter.invoke(RPCRouter.java:146)
               at org.apache.soap.providers.RPCJavaProvider.invoke(
                 RPCJavaProvider.java:129)
               at org.apache.soap.server.http.RPCRouterServlet.doPost(
                 RPCRouterServlet.java:288)
               at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
               at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
               at com.google.gse.HttpConnection.runServlet(HttpConnection.java:237)
               at com.google.gse.HttpConnection.run(HttpConnection.java:195)
               at com.google.gse.DispatchQueue$WorkerThread.run(DispatchQueue.java:201)
            Caused by: com.google.soap.search.UserKeyInvalidException: Key was of wrong size.
               at com.google.soap.search.UserKey.<init>(UserKey.java:59)
               at com.google.soap.search.QueryLimits.lookUpAndLoadFromINSIfNeedBe(
                 QueryLimits.java:217)
               ... 14 more
            '}>
            Traceback (most recent call last):
              File "<stdin>", line 1, in ?
              File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 453, in __call__
                return self.__r_call(*args, **kw)
              File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 475, in __r_call
                self.__hd, self.__ma)
              File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 389, in __call
                raise p
            SOAPpy.Types.faultType: <Fault SOAP-ENV:Server: Exception from service object:
            Invalid authorization key: foo:
            <SOAPpy.Types.structType detail at 14164616>:
            {'stackTrace':
              'com.google.soap.search.GoogleSearchFault: Invalid authorization key: foo
               at com.google.soap.search.QueryLimits.lookUpAndLoadFromINSIfNeedBe(
                 QueryLimits.java:220)
               at com.google.soap.search.QueryLimits.validateKey(QueryLimits.java:127)
               at com.google.soap.search.GoogleSearchService.doPublicMethodChecks(
                 GoogleSearchService.java:825)
               at com.google.soap.search.GoogleSearchService.doGoogleSearch(
                 GoogleSearchService.java:121)
               at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source)
               at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
               at java.lang.reflect.Method.invoke(Unknown Source)
               at org.apache.soap.server.RPCRouter.invoke(RPCRouter.java:146)
               at org.apache.soap.providers.RPCJavaProvider.invoke(
                 RPCJavaProvider.java:129)
               at org.apache.soap.server.http.RPCRouterServlet.doPost(
                 RPCRouterServlet.java:288)
               at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
               at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
               at com.google.gse.HttpConnection.runServlet(HttpConnection.java:237)
               at com.google.gse.HttpConnection.run(HttpConnection.java:195)
               at com.google.gse.DispatchQueue$WorkerThread.run(DispatchQueue.java:201)
            Caused by: com.google.soap.search.UserKeyInvalidException: Key was of wrong size.
               at com.google.soap.search.UserKey.<init>(UserKey.java:59)
               at com.google.soap.search.QueryLimits.lookUpAndLoadFromINSIfNeedBe(
                 QueryLimits.java:217)
               ... 14 more
            '}>
            
            1 你看出錯誤了嗎?調用的語法,參數個數以及數據類型都沒有錯誤。這個問題是應用特定的:第一個參數應該是我的應用許可證,但 foo 不是一個有效的 Google 許可證。
            2 Google 服務器返回的是一個 SOAP 錯誤和一大串特別長的錯誤信息,其中包含了完整的 Java 堆棧跟蹤。記住所有SOAP 錯誤都被標示為 SOAP Faults: errors in configuration (設置錯誤), errors in function arguments (函數參數錯誤),或者是應用特定的錯誤 (這里就是) 等等。在其中埋藏的至關重要信息是:Invalid authorization key: foo (非有效授權許可證:foo)。

            進一步閱讀

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线