Chrome在302重定向的時候對原請求產生2次請求的問題說明

發表於2017-01-04

這個問題應該確確實實是一個Chrome的BUG,我在自己的程式設計環境中發現,並在多個伺服器,多個程式語言的執行環境,以及多個瀏覽器下都測試過,都看到有2次請求出現。為了證明不是自己環境的問題,我也特意去找了一些其他站點,用它裡面的一些會產生重定向的請求來測試。比如這個請求地址http://wenda.golaravel.com/account/openid/qq_login/,這是golaravel問答模組進行qq登入的連結地址,它會重定向到qq授權登入的頁面。

使用fiddler監控wenda.golaravel.com這個站點,然後在Chrome裡面訪問以上地址,回到fiddler檢視監控結果:

459873-20161230175155148-1266323152

從這個結果可以明確地看到,Chrome對這個地址發出了2次http請求,並且這兩次http請求都從伺服器拿到了Response。從fiddler的Statistics欄裡面,可以對比看出這兩個請求過程的一些資訊:
第一個是:

459873-20161230175155961-1377331488
第二個是:
459873-20161230175157179-1273718096
從這個對比結果可以看到,這兩個請求並不是一種序列的關係,而是並行的關係。但是這個問題的特性還不止這麼簡單,目前我發現的一些現象如下:

1)不是每次都會出現這個情況,我只能說大部分測試操作都出現這種情況,但是少部分情況是正常的:訪問302的地址,對原地址只發起了一次請求,第二次是對302 Location指定的地址的請求,這是正常的;
2)這兩個請求並不是每次都能成功從伺服器拿到響應,有的時候其中的一個會報500的錯誤,或者是顯示failed,此時如果觀察fiddler的log記錄,會看到有下面的一些關鍵資訊:

3)大部分情況下,都是這兩個請求先發起,然後再對302 Location重定向請求;但是極少的情況會遇到302重定向請求夾在這兩個請求中間。

目前我並沒有找到這個問題產生的原因,網上相關的資料太少了,所以我只能從多個方面來驗證是否是Chrome本身的問題,最後得出的結論也跟我的猜想一致,這就是Chrome較新版本的一個BUG,我在當前時間點的最新版本的Chrome瀏覽器裡面看到這個現象的:

459873-20161230175158507-68370858

下面我會詳細地證明它是否為Chrome的一個BUG。

1. 問題的發現

我使用laravel框架寫了一個很簡單的程式,就幾個頁面,做微信登入的demo用的,所以頁面裡的微信登入按鈕,實際上就是一個需要重定向到微信授權頁面的地址。我在瀏覽器裡面訪問這個地址的時候,在本地windows下的apache伺服器的access.log裡面,發現這一個訪問操作產生了三次http請求:
459873-20161230175200476-856059715
從這個日誌裡很明顯地看到有2次對/login/weixin的請求,這個就是重定向請求的原請求記錄。發現這個問題之後,我並不認為是伺服器或者瀏覽器的問題,而是首先懷疑是否是自己程式碼裡面有重定向loop的情況。所以第一步就去仔細地檢查自己的程式碼:

最後的redirect方法是:

這個程式碼裡的RedirectResponse是laravel框架提供的類。從這個程式碼,我並沒有看出什麼問題,因為沒有多次建立Response的處理。所以開始懷疑是否是新版的laravel框架的問題,因為我用的是最新的laravel框架。所以我又用公司的php環境測試了一下,公司的php環境用的yii這個php框架,結果發現,公司的環境在本地依然存在這個問題。

為了排除是框架的問題,我又自己寫了兩個最簡單的php頁面:
459873-20161230175202148-820118495
459873-20161230175203507-930459352
我把demo1部署到demo1.com,demo2部署到demo2.com,然後訪問demo1.com來測試。最後也還是遇到了這個問題。在這一次測試裡面,我還發現了有兩個關鍵點:

1)如果把302改成301重定向,那麼chrome就不會產生兩次請求。但是實際上301用在這裡是不對的,因為它的含義是原地址的資源已經永久轉移到別的位置了。
2)這個問題導致的兩次對原地址的請求,大部分情況下,伺服器都能收到並進行處理。(demo1裡面的列印資訊,在這個問題出現的時候,每次都列印兩個時間資訊,說明伺服器響應了2次)。這意味著使用者的一次訪問操作,瀏覽器發出了2個請求,伺服器對同一個使用者操作進行了2次處理。這並不是個沒有影響的事,比如當這個請求對某個資源的狀態做了一些持續性的改變時,如資料累計,那就意味著使用者一次操作,就會累計2次,這樣這些資料結果可能就有問題了。這也是我把這個問題詳細記錄說明的主要原因,我覺得開發中應該注意到這個問題的存在,以便在排除一些疑難的資料問題的時候,可以思考到這個層面上來。

到此為止,基本上已經排除是php框架的問題了。接下來考慮的問題產生物件主要是程式語言,伺服器以及瀏覽器。

2. 排查是否為程式語言的問題

為了驗證是否為php語言本身的問題,我又用express框架寫了以下簡單程式碼,並執行在node的環境裡面來測試:

最後測試發現這個問題,在Nodejs裡面同樣存在。所以也可以排除是php語言的問題了。

3. 排查是否為伺服器的問題

因為這個問題本身是在本地windows伺服器裡面發現的,所以我懷疑是否為本機apache的問題,所以我又把相關的程式碼部署到遠端的nginx伺服器上,最後同樣測試到這個問題的存在。

加上上一步在nodejs裡面測試的時候,實際上是用本機的node伺服器執行的,綜合這兩個伺服器測試結果,也能證明並不是apache伺服器的問題。

4. 排查是否為瀏覽器的問題

我的機子上有360瀏覽器,firefox,IE11,Edge瀏覽器和最新的Chrome瀏覽器的。最後測試發現只有Chrome瀏覽器裡面有這個問題,其它瀏覽器測試,在fiddler裡面都只能看到對原地址僅發起了一次http請求,在每個瀏覽器我都重複做了大概十多次訪問操作才得出這個結論。為了進一步驗證Chrome的版本問題,我又特意刪了當前版本,下載了一個Chrome46的瀏覽器測試,結果沒有發現這個問題。到此為止,也就基本上可以認為是Chrome瀏覽器的問題。

5. 進一步排查是否為本機執行環境的問題

為了進一步排查是自己開發環境的問題,我專門到網上找了一些其他站點的302請求地址做測試。除了本文開頭提供的地址,下面這個地址也可以測試:

http://www.toutiao.com/auth/connect/?type=sso&platform=weixin&next=https://sso.toutiao.com/auth/login_success/?service=http://www.toutiao.com/

459873-20161230175204757-412612590

最後,根據以上的排查內容,可以認定這個問題是Chrome的一個BUG,我已經report給他們了,回不回覆不重要,最重要的是下一個版本這個問題是否能夠解決。所以接下來這個問題,我的處理方式是:跟進chrome的版本更新情況,並在新版本中進行測試。希望它能在後續的版本中得到解決。

其實在以上排查過程中,還有一些情況值的考慮,比如作業系統環境,網路環境的影響,畢竟http請求本身處於這兩個大的因素之下,所以也不能完全排除它們的原因。所以,要是感興趣的朋友,覺得這個問題值得研究的話,非常希望你能把自己的測試結果反饋過來,如果這個問題在你的機器上也存在,那麼就能增加本文的客觀性和正確性,就能幫助更多的人;如果很多人都沒有測試出這個問題,就說明本文的結論有誤,這篇文章應該作廢才行。

相關文章