記一次HTTP POST請求變成GET請求

問題描述

客戶端發(fā)起的HTTP POST請求, 到達服務器后請求方法莫名其妙變成了GET請求, 導致客戶端收到的是404。

問題定位

  1. 首先檢查代碼, 再三確認并且在測試環(huán)境上驗證后確保代碼沒問題。

  2. 因為是生產環(huán)境出現(xiàn)的問題, 便排查測試環(huán)境和生產環(huán)境的區(qū)別:

    1. 兩者客戶端代碼相同
    2. 兩者服務端代碼相同
    3. 生產環(huán)境用Nginx做了域名轉發(fā), 而測試環(huán)境直接使用的IP訪問, 未使用代理

于是嘗試將問題定位在Nginx轉發(fā)上, 馬上重現(xiàn)問題, 并且觀察Nginx日志, 發(fā)現(xiàn)轉發(fā)時出現(xiàn)了如下日志:

[27/Jul/2020:15:53:01 +0800] [訪問的URL] "POST /api/v/game/query HTTP/1.1" 301 185 "-" "PostmanRuntime/7.25.0" "-"
[27/Jul/2020:15:53:01 +0800] [訪問的URL] "GET /api/v/game/query HTTP/1.1" 404 18 "http://訪問的URL/api/v/game/query" "PostmanRuntime/7.25.0" "-"

從上面的日志可以看出:

  1. Nginx收到的請求確實為POST請求, 客戶端請求沒有問題。
  2. 從Nginx到服務端請求發(fā)生了變化: POST被轉換成了GET請求, 由此服務端返回404。

由此可以確定: 問題的出現(xiàn)是因為Nginx的轉發(fā)使HTTP方法類型發(fā)生了變化。

問題原因

那么Nginx為什么會把POST請求轉換成GET請求呢?注意上面的第一行日志中有301的字樣, 301狀態(tài)碼的意思是: 資源位置永久改變, 需要重定向, 通常用于將HTTP請求遷移到HTTPS。

到這里, 回頭看看Nginx的配置文件, 文件中配置了listen 443 ssl, ssl_certificate, ssl_certificate_key等參數(shù), 即Nginx配置的是HTTPS服務, 所有請求將以HTTPS訪問, 對于HTTP請求, 將會被以HTTPS的形式重定向。

再看看客戶端發(fā)起請求的URL, 確實是HTTP請求, 所以觸發(fā)了重定向, 也就導致了問題的產生。

即使通過Nginx將HTTP轉換成了HTTPS, 這里也并沒有解釋為什么POST會變成GET請求, 這里就需要祭出著名的《圖解HTTP》中關于狀態(tài)碼的解釋了:

書中關于3xx狀態(tài)碼的解釋:

1. 301-Moved Permanently(永久性重定向), 該狀態(tài)碼表示請求的資源已經被分配了新的URI, 以后應使用資源現(xiàn)在所指的URI, 也就是說如果已經把資源對應的URI保存為書簽了, 這時應該按Location首部字段提示的URI重新保存。

2. 302-Found(臨時重定向), 該狀態(tài)碼表示請求的資源已經被分配了新的URI, 希望用戶(本次)能使用新的URI訪問。和301不同的是, 302不是永久移動, 只是臨時性質的, 也就是已移動的資源對應的URI將來還有可能發(fā)生改變, 如果URI被保存為書簽, 用戶不需要更新書簽。

3. 303-See Other(存在另一個URI), 該狀態(tài)碼表示請求的資源存在著另一個URI, 應使用GET方法定向獲取請求的資源。303和302功能相同, 但303明確表示客戶端應當采用GET方法獲取資源。比如, 當使用POST方法訪問時, 其執(zhí)行后的處理結果是希望客戶端能以GET方法重定向到另一個URI上去, 則返回303狀態(tài)碼。

4. 304-Not Modified(未滿足條件的URI), 該狀態(tài)碼表示客戶端發(fā)送附帶條件的請求時, 服務器允許請求訪問資源, 如果未滿足條件, 則返回304。

5. 307-Temporary Redirect(臨時重定向), 該狀態(tài)碼與302有相同的意義, 302禁止POST變換成GET, 但是在實際使用中, 大家并不遵循, 仍然將POST轉換成了GET。307會遵照標準, 不會從POST變成GET。

注: 當301、302、303狀態(tài)碼返回時, 幾乎所有的瀏覽器都會把POST改成GET, 并刪除請求報文內的主體, 之后請求會自動再次發(fā)送。即使301, 302禁止將POST方法改成GET方法, 但實際使用中大家仍然將其改成了GET。

到這里, 原因已經很明了了。

問題解決

對于這里的問題場景, 我們不希望POST請求被改成GET請求, 則解決方法有:

  1. 如果可以, 將客戶端發(fā)起的HTTP請求改為HTTPS請求, 這樣便不會重定向。

  2. 將Nginx配置文件中的return 301 $URI永久重定向改為return 307 $URI臨時重定向。

參考資料

  1. stack overflow

  2. 《維基百科》

  3. 《圖解HTTP》

原文鏈接

記一次HTTP POST請求變成GET請求

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容