問題
HTTP明明是跑在TLS之上,怎么會意識到https的存在呢?
太長不看
在HTTP/1.1給正向代理的請求行中,方法后面的參數是 absoluteURI ,而非 http URL,即可以使用任何代理支持的協議。 也就是說,該參數表達的是任何可以識別特定資源的標志,所以https作為一種協議可能會出現在該位置。
文檔規定
在 RFC2616 中,規定請求行的格式為 Method SP **Request-URI** SP HTTP-Version CRLF
,而 Request-URI
的格式為 "*" | absoluteURI | abs_path | authority
。其中,abs_path
是我們最常看到的,例如 /pub/WWW/TheProject.html
,通過聯合請求頭中的HOST字段,我們就可以訪問到資源了。
但有時我們的HTTP請求是給一個正向代理的。HTTP/1.1規定,在這種情況下,Request-URI
必須 absoluteURI 的格式,即 scheme ":" ( hier_part | opaque_part )
。其中,scheme
定義了該URI的命名空間,告訴了代理該資源標識符的語義和語法。所以,它可以是 https:// …
或者 ftp:// …
,甚至可以不指定協議,例如 file:// …
。
同時,為了避免在代理的過程中產生回環, RFC2616 要求代理的實現必須能夠通過 absoluteURI 確定資源所有的服務器/別名,IP地址,主機名等。
設計分析
為什么給正向代理的HTTP請求行中需要URI,而非 abs_path
+ HOST字段?
因為這里只確定客戶端和代理之間是通過HTTP協議通信的,並不知道代理會通過何種方式訪問資源。所以我們需要在HTTP請求行中告知代理URI,如果代理支持對應的訪問,則在成功獲取資源后通過HTTP返回給客戶端。
另外,除了直接請求資源服務器,代理也可能把這個請求交給下一個代理,這之間的通信也可能不是基於HTTP的,只有代理在知道完整URI的情況下才能確保接下來的步驟正確運行。
如果使用絕對URI,是否會和HOST字段的信息產生冗余?
在HTTP/1.1中,HOST字段是強制的。其目的是告知服務端請求資源所在的(虛擬)主機和端口號,例如 Host: www.w3.org
。所以代理請求行中的絕對URI是會和HOST產生信息冗余的。事實上,RFC7230 規定這種情況下代理必須忽略HOST字段信息,並通過請求行中的URI重新填充HOST字段。
為什么實現不良的代理可能會產生回環?
在現在的網絡環境下,CDN/反向代理的情況非常普遍。CDN的邊際網絡會根據請求選擇直接返回緩存或者繼續轉發請求,所以一個請求可能會被多次代理。但是,如果代理無法、或錯誤的判斷資源來源時,就可能發生回環。例如,代理 A 判斷應該把請求交給代理B,但是 B 在接到請求后認為該請求應該交給代理 A ,這樣就形成了回環(也可能有多個節點),最終導致請求被丟棄。
如上圖所示,這種回環的發生不僅導致了數據的丟失,也耗費了大量帶寬和代理的資源。事實上,這也被作為一種對CDN的“杠桿”拒絕服務攻擊。
關於如何通過擴展HTTP頭來解決這個問題,可以參考 Preventing Request Loops Using CDN-Loop 。
后記
回到最初的問題,如上所述,代理對於不同 scheme
的支持完全取決於實現,如果代理無法支持以 https://
開頭的代理請求,則會返回4xx狀態。例如 CDN 提供商 fastly 在4年前就是這樣。