在使用 HttpClient 4.4 調用第三方 http api 時遇到了很多問題,還好最后都解決了,記錄一下遇到的問題及解決辦法,希望對同樣有此問題的你有所幫助。
環境說明
首先說明一點是,對方的測試環境是在公共的網絡環境下部署的,即是對外開放的,需用外網訪問,不支持內網,只支持走專線(目前不考慮這個方式,因為鋪設專線耗時還耗經費)。
所以在調試接口的時候就直接在個人筆記本上使用 POSTMAN 這樣的接口調試工具進行調試。
在微信群里和第三方聯調,對方告訴我們需要調用哪幾支接口,然后我們就按照接口文檔去調試了。
調試的過程中發現了很多的問題。例如,對方並沒有口頭或文檔說明需要傳APPID、APPKEY和一些其他參數,這些參數是放在Head頭部的,三方沒有提前告訴我們需要這些參數,我們在聯調時發現接口報異常【APPID 不能為空】,然后就把這個問題發到群里,半天才回復,而且是他們內部互相踢皮球,搞了半天才確定誰去解決。
不就是在系統里創建一個appid和密鑰嘛,結果第二天下午才給搞好。這效率真是沒法說,而且我覺得既然跟我們合作(我們是強勢方),你就把需要的東西都准備好了,有啥問題積極回答、解決,這樣效率也高。
這個問題解決了,需要調的接口通過 POSTMAN 很快就都調試了一遍,沒啥大問題都正常通過聯調,接下來就是通過代碼調用了,還有處理一些細節的東西。
解決文件上傳發送multipart/form-data請求
由於對方測試環境是部署在外網,我們公司的開發環境是在公司的內網,而且必須在公司的內網里開發(不然連不上數據庫項目啟動不了),這個問題是沒辦法解決的,所以就干脆先在自己的筆記本電腦上把代碼寫完,再傳到公司開發機上。
剛開始打算使用 Java 自帶的 java.net.HttpURLConnection 那一套方式,但是調第二個接口時發現需要上傳文件,content-type需要為 multipart/form-data。
如果還繼續使用 java.net 包下的那一套就會非常麻煩,因為上傳文件和普通參數不一樣,需要有分割符來分割文件以及普通參數,因為服務端需要知道文件從哪開始到哪結束。
這些工作需要客戶端程序來處理,如果還繼續用java.net包下的類,將會使此工作開發起來很麻煩,所以最后選擇使用 HttpClient 工具包來處理這個問題。
HttpClient 是 Apache 軟件基金會下的開源項目,是目前較流行和好用的 http 網絡請求工具包,遵循Java面向對象編程的原則。。。關於 HttpClient 就不多說了,想了解的自行百度下。
HttpClient封裝了發送 multipart/form-data 類型的請求的實現細節,具體使用方法見這篇文章。
在 HttpClient 的幫助下,基本代碼已經寫完且相關接口都已經通過代碼的方式調通了。
解決代理及 400 Bad request
於是便把代碼上傳至公司的開發機,准備完善一些細節處理。
等這些工作都做完時,委托同事開通的代理服務器到第三方IP的網絡策略也都已經搞完(開發機、測試環境都是內網環境,不能直連互聯網,故需通過代理服務器來訪問目標地址,到時候線上也一樣。我們的開發機訪問不了代理服務器,所以只能在測試環境測)。
把代碼提交后部署到測試環境后,我已經迫不及待的想要測試一下了。這是第一次測試這個功能,我記得是失敗了,報錯,400 Bad request。這是什么問題?參看這篇,但是網上說的最多的兩種情況,都和我的不符,所以在這篇文章也找到了解決辦法。
因為我測試環境走的代理,在自己筆記本聯調時是互聯網直連的,所以沒有此問題。通過查看代碼,我發現我設置代理的時候用的默認的 HTTP 協議,而我要訪問的目標地址是 HTTPS 的,所以我懷疑是這的問題。於是我就把目標地址改為HTTP 方法請求(對方也支持HTTP),果然好了。但這樣又引發了其他問題,且看下面。
解決 502 Bad Getway
接下來的很多次,再去測試的時候,發現很多時候都是報超時,Read timeout, 因為我設置的等待響應的時間是10秒。我把這個設置去掉之后,大概等30秒,返回的錯誤是 502 Bad Getway
502 Bad Gateway是指錯誤網關,無效網關;在互聯網中表示一種網絡錯誤。表現在WEB瀏覽器中給出的頁面反饋。含義:這通常並不意味着上游服務器已關閉(無響應網關/代理) ,而是上游服務器和網關/代理使用不一致的協議交換數據。鑒於互聯網協議是相當清楚的,它往往意味着一個或兩個機器已不正確或不完全編程。
這是什么錯?無從下手啊。
想着是不是還是協議不一致導致的?於是我又把協議這方面的 http 對 https ,這樣互相排列組合的改了幾次還是不行。
然后我就在網上搜這個問題咋解決,無意中在一個國外的網站行看到有人問這個問題咋解決
其中一個回復說【您可能正在使用代理來獲取ssl內容,但您的代理設置是錯誤的。您應該考慮使用http作為代理方案,然后使用https作為實際內容的方案。這解決了我的問題】
說的好准,確實使用了代理。
解決證書問題-javax.net.ssl.SSLException:Unrecognized SSL message,plaintext connection?
於是把代理又改成 HTTP 的,然后又拋異常:jvax.net.ssl.SSLException:Unrecognized SSL message,plaintext connection?
查了一下意思是說,無法識別 SSL 信息,明文連接?原來是證書方面的問題,要加一下代碼,使其信任所有證書,具體怎么加看這篇。
然后按這篇文章加了信任所有證書就好了。
總結
之前對 Http 接口不是太了解,基本上沒怎么用過,通過這次認識到了自己在這方面的知識很欠缺,要好好補一補了。