HTTP請求重發


HTTP 協議中,從語義上講, GET 請求一般是獲取服務器端的資源,不會對服務器數據造成副作用,可簡單理解為一種“讀”操作;而 POST 請求多用於更改(增、刪、改)服務器上的資源,會產生一定的副作用。

所以,這樣看起來,瀏覽器是不是就不會因為網絡原因啥的自動重發 POST 請求吧?實際上是這樣么?

起因

最近在對接地圖的一個數據錄入接口:前端向后端發送一個 CSV 文件,后端將 CSV 文件中的數據解析出來,然后將數據通過地圖接口導入到地圖數據庫。由於地圖提供的接口有點怪異,批量導入數據的接口有一些問題,只能使用單條導入接口,所以在這里, CSV 文件里面有多少條數據,就會訪問多少次地圖的接口。

雖然有點坑,不過問題究竟是解決了,於是就這樣上線了。

天有不測風雲,遇到一個客戶,一下要導入上千條數據,后端這樣串行地一條一條去導入,很輕易地就花了好幾分鍾。而且還遇到一個詭異的現象:每條數據都導入了兩次!

分析

憑借多年的前端開發經驗(不要臉了),立馬大膽猜測,瀏覽器發送了兩次請求。

於是先到谷歌開發者工具的 Network 標簽頁檢查一下請求,發現此處只記錄了一次請求,並且該請求沒有響應,好像看不出來什么貓膩。再切換到 chrome://net-internals/ 中看看日志,發現一個 error code , google 了一下,並沒有什么結果,看起來也驗證不了猜想。

然后再去找后端同學看看接口日志,是不是訪問了兩次,后端同學似乎稍微有點不太想打日志重新部署(過程比較麻煩),所以先放棄用這種方式求證。

那用啥求證呢? Charles 吧。

在 Charles 中一看,發現發了四次請求,每次請求基本上都耗時六十多秒,每次都沒有響應內容。

好了,看起來就是瀏覽器六十秒超時重發請求。

深入分析

可以轉念一想,這對么?

  • 1、 POST 請求就這樣輕易地被瀏覽器超時重發,難道瀏覽器開發者沒考慮過數據重復發送的問題嗎?表單 POST 請求手動刷新瀏覽器的時候都會彈窗提醒用戶要不要重復提交數據呢!
  • 2、為啥是六十秒呢?時間這么短嗎?想想平時本地斷點調試服務器代碼的時候,那可是會超時老長時間的,所以這六十秒算個啥呢?

搜一搜往上資料,發現 HTTP/1.1 的一處規范

If an HTTP/1.1 client sends a request which includes a request body, but which does not include an Expect request-header field with the "100-continue" expectation, and if the client is not directly connected to an HTTP/1.1 origin server, and if the client sees the connection close before receiving any status from the server, the client SHOULD retry the request.

大致意思就是說,如果發送一個請求到服務器端,該請求有請求體,但是請求頭里面不包含“ 100-continue ”這種東西,並且客戶端沒有直接連接到原始的 HTTP/1.1 服務器,此時,如果客戶端在接收到服務器發送的 HTTP 狀態之前發現服務器主動關掉連接,那么客戶端應該重試請求。

那看起來好像就是服務器端主動關掉了連接,導致瀏覽器重新發送請求了。

我們服務器端使用的是 Tomcat ,查一查資料,發現 Tomcat 默認的 connector 超時時間是六十秒,剛好吻合上了。

問題原因找到了,解決起來就輕松了,此處不贅述。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM