之前和客戶方一套系統連接webservice經常出現連接超時的問題,至於連接為何超時,雙方各執一詞,誰吃飽撐得往自己身上攬臟水啊。
由於之前沒有對腳本的執行時間進行超時處理,導致系統操作人員陷入無限等待中,所以在連接webservice時添加了終端操作,當連接超過限定時間時,認為連接失敗阻塞了,就放棄連接。
1 ini_set('default_socket_timeout', 13); 2 set_time_limit(15); 3 $errno = ini_get('error_reporting'); 4 error_reporting(0); 5 register_shutdown_function('runError');//和諧輸出頁面執行超時錯誤 6 $time_start = microtime(true); 7 try{ 8 $client = new soapclient(C('webservice_url')); 9 $client->soap_defencoding = C('webservice_encoding'); 10 $client->xml_encoding = C('webservice_xml_encoding'); 11 $username = C('webservice_u'); 12 $password = C('webservice_p'); 13 $aryResult = $client->__soapCall("ImportOrder", array(array('username' => $username, 'password' => $password, 'ordermesg' => $list, 'datatype' => 'json'))); 14 error_reporting($errno); 15 $time_request = (microtime(true)-$time_start); 16 }catch(Exception $e){ 17 $time_request = (microtime(true)-$time_start); 18 if($e->getMessage() == 'Error Fetching http headers' && ini_get('default_socket_timeout') < $time_request) { 19 throw new SoapTimeoutException('webservice連接可能超時'.' It took '.$time_request.' and the limit is '.ini_get('default_socket_timeout') ); 20 } 21 // E: Not a timeout, let's rethrow the original exception 22 throw $e; 23 }
1 function runError () { 2 echo '程序執行超時,請重新打開'; 3 }
程序的超時有兩種,首先是webservice連接本身建立通訊了,但是一直沒有返回數據,所以上面的代碼中定義了webservice的連接超時時間為13s,這是定義在php.ini中的,如果webservice連接超過13s,程序就拋出連接超時的異常。
另外一種是腳本執行超時,有時候可能是瀏覽器,網絡等各種原因,webservice還沒有連接,腳本就陷入了假死狀態,所以定義腳本超時時間,系統默認腳本執行時間為30s,這邊定義為15s,手冊上有提到,當調用set_time_limit時,計時器會從0開始計時,前面各種元素加載的時間並不計算在內。此處結合上面的webservice連接超時時間,如果webservice連接上了后產生阻塞,13s內便會拋出異常,所以不會引起15s才觸發的腳本中斷。所以,如果腳本中斷基本可以認定webservice沒有連接成功。當然,我們查看過webservice連接情況,正常情況下,2s內連接的建立,數據的返回都完成了,所以現有的設計基本不會引起太大的問題。不過,這也只是猜測,前段時間由於數據量較多,網絡又延遲,webservice連接成功后沒有及時返回數據,也沒有達到13s的連接超時,但是由於前面建立連接時花了不止2s,腳本執行到15s時,中斷了腳本,再重建連接返回了非預期的數據。所以,如果願意等待的話,這兩者之間的時間最好可以相差大點。
腳本中斷后系統會報錯,所以,這邊還有個處理技巧,先記下當前的報錯級別,然后重置為0,即不報任何錯誤,不自動拋出異常,然后腳本超時后,調用register_shutdown_function注冊一個自定義函數,超時后會自動調用這個函數,顯示自定義的信息。當然,如果webservice連接成功的話,還是需要回復先前的錯誤級別,不然,webservice連接超時后的異常將無法捕獲。
這個一個相對簡單而完善的連接處理就建立好了。