剛才在做hexo頁面優化,發現了本地測試返回http 307。以前沒見過這個響應碼,於是做一下調研。
相關文章:
http 307
在rfc規范中,http 307 Temporary Redirect 是臨時重定向。
平時常見的重定向是:
- 301:Permanently Moved,永久重定向
- 302:Temporarily Moved,臨時重定向
http 307和302的區別在於:307要求客戶端不改變原先的請求方法,對在Location頭部中規定的URI進行訪問。對於302,很多客戶端的實現是,直接使用GET方式訪問重定向地址。
例子
客戶端請求
1 |
POST /index.php HTTP/1.1 |
服務器端響應
1 |
HTTP/1.1 307 Temporary Redirect |
那么客戶端必須以POST方式重定向訪問https://www.example.org/
。
本地測試產生http 307
next的_config.yml
配置
1 |
# Internal version: 2.1.5 & 3.5.7 |
平時寫url地址,一般是http或者https,但是next里面的例子都是//
。
//
的意義是,沿用當前頁面的協議。如果當前頁面是http協議,那么發出去的請求就是http;如果是當前頁面是https,那么發出去走https。//
寫法的好處是,不需要關注協議,只需要關注URI路徑。如果哪一天發生協議變更,比如http升級為全站https,那么代碼完全都不用修改。
但是這沒有解釋為什么返回了http 307。
仔細看看response header,除了Location
指示重定向地址外,還有
1 |
Non-Authoritative-Reason: HSTS |
HSTS是HTTP嚴格傳輸安全(英語:HTTP Strict Transport Security),之前的文章提到過:
因為本地測試,使用http://localhost:4000
訪問,所以//
的頁面協議是http。但是cloudflare.com開啟了HSTS,所有請求都必須是https協議。對cloudflare.com原來的http請求必須升級為https。
事實上,這個307響應不是cloudflare.com產生的,是chrome瀏覽器干的好事。
The way Chrome shows this in the network tab is by creating a dummy 307 response with a redirect to the https version of the address. But that’s a fake response and is not generated by the server - the reality is Chrome did that internally before the request even went to the server.
注意到,rfc定義http 307是Temporary Redirect,而截圖顯示的是Internal Redirect。 回想到HSTS只在第1次http訪問之后才會生效。如果chrome不做這個返回,會是怎樣的流程呢:
- 本地客戶端http方式訪問cloudflare.com
- 服務器表示要以https方式訪問資源
- 於是本地客戶端以https方式再次訪問cloudflare的資源
中途多了一次網絡請求。
因為chrome維護了一份HSTS站點列表,知道cloudflare必須要https方式請求。於是截獲http請求后,直接以https方式訪問,同時做出dummy 307響應。
小實驗
把next的_config.yml
從//
修改為https://
,再測試
直接就是http 200了。
小結
//
比寫死具體http、https更加靈活,推薦使用- http 307 Temporary Redirect,臨時重定向,客戶不能改變請求方式
- chrome知道HSTS站點,會自動把這些站點的http請求改寫為https,同時在response header增加
Non-Authoritative-Reason: HSTS
,並且把307響應碼解析為Internal redirect
本文作者ycwu314,備份地址 https://ycwu314.github.io/p/http-307/