HTTP 協議中,從語義上講, GET 請求通常是獲取服務器端的資源,不會對服務器數據形成反作用,可簡單理解爲一種「讀」操做;而 POST 請求多用於更改(增、刪、改)服務器上的資源,會產生必定的反作用。html
因此,這樣看起來,瀏覽器是否是就不會由於網絡緣由啥的自動重發 POST 請求吧?其實是這樣麼?前端
最近在對接地圖的一個數據錄入接口:前端向後端發送一個 CSV 文件,後端將 CSV 文件中的數據解析出來,而後將數據經過地圖接口導入到地圖數據庫。因爲地圖提供的接口有點怪異,批量導入數據的接口有一些問題,只能使用單條導入接口,因此在這裏, CSV 文件裏面有多少條數據,就會訪問多少次地圖的接口。chrome
雖然有點坑,不過問題到底是解決了,因而就這樣上線了。數據庫
天有不測風雲,遇到一個客戶,一下要導入上千條數據,後端這樣串行地一條一條去導入,很輕易地就花了好幾分鐘。並且還遇到一個詭異的現象:每條數據都導入了兩次!後端
憑藉多年的前端開發經驗(不要臉了),立馬大膽猜想,瀏覽器發送了兩次請求。瀏覽器
因而先到谷歌開發者工具的 Network 標籤頁檢查一下請求,發現此處只記錄了一次請求,而且該請求沒有響應,好像看不出來什麼貓膩。再切換到 chrome://net-internals/ 中看看日誌,發現一個 error code , google 了一下,並無什麼結果,看起來也驗證不了猜測。服務器
而後再去找後端同窗看看接口日誌,是否是訪問了兩次,後端同窗彷佛稍微有點不太想打日誌從新部署(過程比較麻煩),因此先放棄用這種方式求證。網絡
那用啥求證呢? Charles 吧。工具
在 Charles 中一看,發現發了四次請求,每次請求基本上都耗時六十多秒,每次都沒有響應內容。google
好了,看起來就是瀏覽器六十秒超時重發請求。
能夠轉念一想,這對麼?
POST 請求就這樣輕易地被瀏覽器超時重發,難道瀏覽器開發者沒考慮過數據重複發送的問題嗎?表單 POST 請求手動刷新瀏覽器的時候都會彈窗提醒用戶要不要重複提交數據呢!
爲啥是六十秒呢?時間這麼短嗎?想一想平時本地斷點調試服務器代碼的時候,那但是會超時老長時間的,因此這六十秒算個啥呢?
搜一搜往上資料,發現 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 超時時間是六十秒,恰好吻合上了。
問題緣由找到了,解決起來就輕鬆了,此處不贅述。