真正「搞」懂HTTP協定11之代理服務

2023-02-09 12:04:22

  代理,其實全稱應該叫做代理伺服器,它是使用者端與伺服器之間得中間層,本質上來說代理就是一個伺服器,在HTTP的鏈路中插入的一箇中間環節,就是代理伺服器啦。所謂的代理服務就是指:服務本身不生產內容,而是處於中間位置轉發上下游的請求和響應,具有雙重身份。面向下游的使用者時,表現為伺服器,代表源伺服器響應使用者端的請求。而面上上游源伺服器時,又表現為使用者端,代表使用者端傳送請求。

  我們發現,其實代理伺服器在中間既是使用者端,又是伺服器,那麼其實他就可以在請求或響應經過它的時候,夾帶上一些額外的東西。

  代理有很多種類,比如匿名代理、透明代理、正向代理、反向代理。

  而我們最常聽說的,就是正向代理和反向代理,其中正向代理其實代理的是使用者端,伺服器不知道真正的使用者端是誰,使用者端對伺服器隱蔽。而反向代理則代理的是伺服器,使用者端不知道源伺服器是誰。而反向代理則是現代伺服器技術的基本實踐了,幾乎各個應用的伺服器都會搞一下反向代理。

  反向代理在傳輸鏈路中更接近源伺服器,為源伺服器提供代理服務,我們今天講的其實就是反向代理。

一、代理的作用

  我們簡單的瞭解了代理的概念,那麼接下來我們看看代理有啥用處呢?或者說反向代理的作用是什麼呢?

  我記得我之前說過,在最開始講網際網路分層模型的時候,電腦科學領域裡的任何問題,都可以通過引入一箇中間層來解決,如果一箇中間層解決不了,那就再加一層。哈哈哈哈,所以不僅僅是在TCP/IP模型中是這樣,在代理中也是這樣。

  代理(以下所有的「代理」都指反向代理,不再重複)一個最基本的功能就是負載均衡,因為反向代理在面向使用者端得時候遮蔽了真實伺服器,使用者端看到的只是代理伺服器,源伺服器究竟有多少臺、是哪些IP地址都不知道,於是伺服器就可以掌握請求分發的大權,決定由哪一臺隱藏在背後的伺服器去響應請求。

  代理中常用的負載均衡演演算法大概有輪詢、一致性雜湊等,大家瞭解下就行了,這些演演算法的目標都是儘量把外部的流量合理的分散到多臺源伺服器,提高系統的整體資源利用率和效能。

  在負載均衡的同時,代理服務還可以執行更多的功能,比如:

  • 健康檢查:使用「心跳」等機制監控後端伺服器,發現有故障就及時「踢出」叢集,保證服務高可用;
  • 安全防護:保護被代理的後端伺服器,限制 IP 地址或流量,抵禦網路攻擊和過載;
  • 加密解除安裝:對外網使用 SSL/TLS 加密通訊認證,而在安全的內網不加密,消除加解密成本;
  • 資料過濾:攔截上下行的資料,任意指定策略修改請求或者響應;
  • 內容快取:暫存、複用伺服器響應。

二、代理相關頭欄位

  代理的好處很多,因為它欺上瞞下的特點,所以對上下游都隱藏了很多資訊,但是如果雙方想要獲得這些資訊怎麼辦呢?

  首先,代理伺服器需要用Via欄位來表明代理的身份。

  Via是一個通用頭欄位,使用者端和伺服器都可以使用,沒經過一個代理節點,代理伺服器就會把資訊增加到欄位末尾,有點像蓋章的感覺。如果通訊鏈路中又很多代理,就會在Via中形成一個連結串列,這樣就可以知道報文究竟經過了多少環節才到達了目的地。

  假設我們的中間代理有兩個:proxy1和proxy2,當用戶端傳送請求到伺服器時,會經過這兩個代理,那麼Via欄位就是這樣的:

Via: proxy1, proxy2

  等到伺服器傳送響應報文的時候,到達使用者端的就是這樣的:

Via: proxy2, proxy1

  但是Via欄位只解決了使用者端和源伺服器判斷是否存在代理的問題,還不能知道對方的真實資訊。

  但是,伺服器的資訊必然應該是保密的,一般不會讓使用者端知道。但是往往伺服器要知道使用者端的一些真實資訊,比如IP地址啥的,用來做人物誌,統計分析等等。

  可惜的是,HTTP標準裡並沒有定義相關的頭欄位,但是已經出現了很多「事實上的標準」,最常用的兩個頭欄位就是「X-Forwarded-For」和「X-Real-IP」。

  "X-Forwarded-For"的字面意思是「為誰而轉發」,形式上和「Via」差不多,也是沒經過一個代理節點就會在欄位裡追加一個資訊。但「Via」追加的是代理主機名或者域名,而「X-Forwarded-For」追加的是請求方的IP地址。所以在欄位最左邊的IP地址就是使用者端的地址。

  「X-Real-IP」是另一種獲取使用者端真實 IP 的手段,它的作用很簡單,就是記錄使用者端 IP 地址,沒有中間的代理資訊,相當於是「X-Forwarded-For」的簡化版。如果使用者端和源伺服器之間只有一個代理,那麼這兩個欄位的值就是相同的。

  除了"X-Forwarded-For"和「X-Real-IP」還有「X-Forwarded-Host」和「X-Forwarded-Proto」,它們的作用與「X-Real-IP」類似,只記錄用戶端的資訊,分別是使用者端請求的原始域名和原始協定名。

三、代理協定

  有了"X-Forwarded-For"等欄位,源伺服器就可以拿到準確的使用者端資訊了。但是你發現一個問題沒有,這些資訊都是寫在HTTP頭裡的,換句話說,通過這些欄位來操作代理資訊就需要解析HTTP頭,然後再在解析的頭裡去修改HTTP頭,這對代理來說就需要較高的成本了,我本來需要做的就只是轉發一下,現在你還要讓我讀一下,改一下,肯定會降低代理轉發的效能,原來我一秒能傳幾百次,結果經歷瞭解析和修改的過程,只能傳幾十次了。

  再有一個就是,「X-Forwarded-For」等欄位,必須要修改原始報文,但是其實有些情況是不允許甚至不可能修改的,比如應用HTTPS加密報文,要知道現在正經的瀏覽器站點,幾乎全部使用HTTPS。

  所以就出現了一個專門的「代理協定」(The PROXY protocol),它由知名的代理軟體 HAProxy 所定義,也是一個「事實標準」,被廣泛採用(注意並不是 RFC噢)。「代理協定」有 v1 和 v2 兩個版本,v1 和 HTTP 差不多,也是明文,而 v2 是二進位制格式。今天只介紹比較好理解的 v1,它在 HTTP 報文前增加了一行 ASCII 碼文字,相當於又多了一個頭。

  這一行文字其實非常簡單,開頭必須是「PROXY」五個大寫字母,然後是「TCP4」或者「TCP6」,表示使用者端的 IP 地址型別,再後面是請求方地址、應答方地址、請求方埠號、應答方埠號,最後用一個回車換行(\r\n)結束。就像這樣:

PROXY TCP4 1.1.1.1 2.2.2.2 55555 80\r\n
GET / HTTP/1.1\r\n
Host: www.zaking.com\r\n
\r\n

  伺服器看到這樣的報文,只需要解析第一行就可以拿到使用者端地址了,不需要再去解析整個HTTP報文,省了很多資料。

  不過代理協定並不支援「X-Forwarded-For」的鏈式地址形式,所以拿到使用者端地址後再如何處理就需要代理伺服器與後端自行約定。

四、小結

  本篇,我們瞭解了下代理是什麼,以及反向代理在HTTP中所應用的一些請求頭。理解上來說並不複雜,就是記錄代理鏈路中必要的資訊。那麼下面我們來通過問題回憶一下本篇的內容和知識。

  1. 我們學習了Via以及X-Forwarded-For、X-Real-IP等關於代理的欄位,那麼其中哪些是HTTP協定所定義的?哪些只是「事實標準」呢?
  2. 除了X-Forwarded-For、X-Real-IP你還知道哪些關於代理的頭欄位呢?
  3. 代理協定是啥東東?

  好啦,本篇就到這裡了,下一篇是關於HTTP/1.1的最後一篇文章啦~~