Nginx學(xué)習(xí):代理模塊(一)基本配置與概念來了來了它來了。要說 Nginx 最早最出名的名頭是什么?相信不少老碼農(nóng)馬上就會想到,最開始,Nginx 的名頭就是一款性能最高的 反向代理 服務(wù)器。現(xiàn)在其實也是,但是這么說的人越來越少了。也就是說,其實 Nginx 最主要的功能就在于反向代理。如果是編程小白,剛剛從事編程相關(guān)工作,沒有配置過負(fù)載集群,可能對這個概念還是比較陌生的。那么今天咱們就來先說說 代理、反向代理、正向代理 這些概念。 今天的內(nèi)容只有一個配置指令,只能用在 location 中。 代理代理是啥意思,之前我們老早就學(xué)過的設(shè)計模式系列的文章中,就講過一個 代理模式 的應(yīng)用。說實話,Nginx 中的代理模塊其實也是代理模式思維的一個體現(xiàn)。還記得代理模式的定義嗎?
從編程語言的角度來說,就是我們要訪問一個對象,但是可能由于種種原因不能直接訪問它,這就要通過代理來實現(xiàn)訪問。這個代理相當(dāng)于是中間的一個媒介,可以幫我們做一些事情,也可以想像是我們和要使用的對象之間的橋梁。 當(dāng)時我們也舉了一個例子,現(xiàn)在也可以用這個例子,那就是買房子或者買保險,不管是房產(chǎn)中介還是保險銷售,其實都可以稱為代理人。他們用他們專業(yè)的知識幫我們解決問題,甚至買房或者租房都可以不用和房主產(chǎn)生交集,但真正在處理這個房產(chǎn)證的,其實還是房主(保險公司)。 這個就是代理,說起來很抽象是吧,大家都是碼農(nóng),可以先通過代碼去了解,小伙伴們可以回到 PHP設(shè)計模式之代理模式https://mp.weixin.qq.com/s/0CvVMuP-_j-0sqRK_4kcZA 這篇文章中再重溫一下哦。 正向代理與反向代理好了,接下來是另外兩個概念,正向代理與反向代理。 正向代理這個太好解釋了,碼農(nóng)們都喜歡用 Google 吧,因為一些眾所周知的原因,我們沒法直接訪問,因此,大家也都會找一些工具方法來訪問一些不可說的網(wǎng)站。在這種情況下,是需要下載一些軟件,或者配置一些東西,讓我們的瀏覽器通過代理,將請求先發(fā)送到一個外部服務(wù)器,然后由它再轉(zhuǎn)發(fā)請求到目的站點,這個過程就是正向代理。另外,還有一些游戲加速器,以及我們做開發(fā)經(jīng)常會用到的 Fiddler 以及 Charles 抓包工具,這些也都是正向代理軟件。 簡單來說,正向代理需要我們客戶端去配置東西,或者使用軟件,將請求發(fā)送到指定的地方。
比如說,我們現(xiàn)在通過瀏覽器請求 Google 的網(wǎng)址,代理軟件攔截請求,然后發(fā)送到代理服務(wù)器。代理服務(wù)器接收到后,再將請求發(fā)送到真實的 Google 的服務(wù)器,處理完成后, Google 返回的響應(yīng)發(fā)送回代理服務(wù)器,代理服務(wù)器再將請求返回給客戶端。 這就是正向代理,另外還有一種透明代理,意思就是這個代理服務(wù)器像是透明的一樣,只轉(zhuǎn)發(fā),不做別的事情,就和我們正常訪問目標(biāo)網(wǎng)址一樣。 一句話,控制權(quán)在用戶,安裝啟用了代理就走代理,不裝不用不會走代理。 反向代理說完正向的,反向的就好理解了,它和正向代理就是反過來的嘛。不需要我們在客戶端配置或者下載什么軟件,訪問的地址還是原來那個,只不過服務(wù)器上將我們的請求又轉(zhuǎn)發(fā)給了別的服務(wù)器。這個過程對于我們這些用戶是無感知的。
反向代理不需要在客戶端裝軟件,是由網(wǎng)站來控制用戶看到的內(nèi)容。假如我的網(wǎng)站,www.zyblog.com.cn ,通過反向代理到了 Google ,那么大家訪問我的這個網(wǎng)址,實際上打開的會是 Google 的頁面。但是說實話,中文搜索分詞百度還是有優(yōu)勢的,哪天一高興,我再將我的網(wǎng)站反向代理到 Baidu ,那么用戶不需要換別的網(wǎng)址,還是繼續(xù)訪問 www.zyblog.com.cn ,看到的就會是百度的內(nèi)容。 一句話,控制權(quán)在站長,不在用戶,用戶訪問的地址不變,但是會顯示什么,需要代理到哪里,是后端人員控制的。 再拿實際的業(yè)務(wù)來說,很多門戶網(wǎng)站其實是會把一些頻道外包的,比如說體育、健康頻道,它們的記者和資源其實也是有限的。一些小的頻道或者不是熱門的頻道就直接讓第三方公司來做。這時候,有一種方案是直接使用二級域名指到合作公司的服務(wù)器上,而另一種方案,不改變域名,直接將某個路徑,比如 /sports/ 這樣的反向代理到合作公司指定的地址路徑上就可以了。這是很常見的一種業(yè)務(wù)需求。 而大家做為碼農(nóng),接觸到的更多的業(yè)務(wù)需求,則是用于負(fù)載均衡以及后端程序的代理。負(fù)載均衡的問題我們后面講服務(wù)器組的時候再說,先來說說后端程序的問題。 因為我是 Java/.NET 出身,工作一年之后才轉(zhuǎn)的 PHP ,所以對前面兩種語言還是略有了解。除了它們之外,現(xiàn)在的 Go 語言以及經(jīng)典的 C/C++ 這些編譯型語言,都是需要編譯之后才能運行的。它們并不像 PHP 一樣可以通過 FastCGI 直接運行。而且大部分情況下,它們運行后都會直接啟動一個服務(wù),比如說直接運行 jar 包或者直接運行 go 編譯文件。這時,一般會啟動一個端口,通過這個端口就可以訪問服務(wù)。 通常來說,你要是直接在代碼中把端口設(shè)置成 80 ,那么其實這些程序也可以對外服務(wù)的。但是,這些動態(tài)服務(wù)程序普遍對靜態(tài)資源的處理都很差,而且,也不太靈活,比如說我在一臺服務(wù)器上要啟動多個應(yīng)用,也沒辦法同時使用 80 端口。因此,大部分情況下,它們也會借助 Nginx 的反向代理來實現(xiàn)服務(wù)的部署。比如說,我們用 Java 啟動了三個程序,分別使用 8080、8081、8082 三個端口,然后在 Nginx 中,直接反向代理,通過不同的 location 路徑,使用統(tǒng)一的一個 80 端口對外服務(wù)就好了。 proxy_passNginx 中,代理模塊是一個非常重要的模塊,全稱是 ngx_http_proxy_module ,是非常大也非常重要的一個模塊。其實在之前講 FastCGI 時就講過,它也是個代理模塊,只不過是通過 FastCGI 協(xié)議代理的。而 Proxy 模塊則是通用代理,使用 http 或 https 協(xié)議就可以,在 HTTP 模塊中的 Proxy 是七層負(fù)載的代理協(xié)議,Nginx 現(xiàn)在也有四層負(fù)載的 Stream 模塊,它里面也有一個代理子模塊,可以做四層負(fù)載均衡。 好了,點題一下,其實要配置一個反向代理,使用一個 proxy_pass 配置指令就可以了。就這么簡單,我們先來看它的介紹,后面再進(jìn)行演示。這個指令只能配置在 location 以及帶條件判斷的 location 和 limit_except 下面,一般來說,就是 location 為主啦。 這個配置指令的作用就是設(shè)置代理服務(wù)器的協(xié)議和地址以及位置應(yīng)映射到的可選 URI。作為協(xié)議,可以指定“http”或“https”。地址可以指定為域名或 IP 地址,以及可選的端口: 或作為在單詞“unix”之后指定并用冒號括起來的 UNIX 域套接字路徑: 如果一個域名解析為多個地址,則所有這些地址都將以循環(huán)方式使用。此外,可以將地址指定為服務(wù)器組。 參數(shù)值可以包含變量。在這種情況下,如果將地址指定為域名,則在所描述的服務(wù)器組中搜索該名稱,如果未找到,則使用解析器確定該名稱。 注意,這里比較重要。請求 URI 被傳遞給服務(wù)器,如下所示:
在某些情況下,無法確定要替換的請求 URI 部分:
在這種情況下,指令中指定的 URI 將被忽略,并將完整更改的請求 URI 傳遞給服務(wù)器。
WebSocket 代理需要特殊配置,并且從 1.3.13 版本開始支持。 上面的官方文檔的內(nèi)容中,最后關(guān)于 URI 的部分比較重要,需要詳細(xì)看一下。接下來,我們就自己配置一下試試。 配置一個反向代理首先,咱們配置一個 Server 吧,監(jiān)聽 8027 端口,然后反向代理到本機(jī)的 80 端口,這是最簡單的配置,就是本機(jī)之間不同端口的配置。 或者,這樣寫也可以,反正是本機(jī)代理嘛。 直接使用 localhost 也是可以的。你可以訪問一個 PHP 頁面,然后打印 反向代理到外網(wǎng)將 proxy_pass 改成一個外網(wǎng)地址就可以了。 現(xiàn)在打開 http://192.168.56.88:8027/ 就會顯示新浪的頁面。 負(fù)載均衡反向代理上面測試了本機(jī)和外網(wǎng),內(nèi)網(wǎng)其它主機(jī)也是可以的,我們可以復(fù)制一臺虛擬機(jī),然后設(shè)置 IP 為 192.168.56.89 ,部署好 Nginx 應(yīng)用,并且準(zhǔn)備一個 index.html 和一個 1.php 文件。注意這兩個文件要與 88 主機(jī)上的內(nèi)容不同,這樣才方便一會我們的測試。 先來試試直接代理到 89 上。 訪問之后可以正常打開 89 主機(jī)上相關(guān)的內(nèi)容。然后我們就來測試下負(fù)載均衡,需要在 http 模塊下配置一個 upstream 。 這個配置我們后面再學(xué),現(xiàn)在你只要知道,它第一個參數(shù)是服務(wù)器組的名字,后面花括號內(nèi)部的通過 server 指定多臺服務(wù)器,形成一個服務(wù)器組。默認(rèn)的均衡策略是輪詢,也就是請求第一次走 88 的 80 端口,第二次再請求走 89 ,不寫端口號默認(rèn)也是 80 端口。 然后直接 proxy_pass 代理指向這個服務(wù)器組就好了。 現(xiàn)在再次訪問,就會發(fā)現(xiàn)每次刷新,都會在 88 和 89 不同的頁面之間切換。這就是最簡單的負(fù)載均衡配置了。如果我們訪問一個 88 存在,而 89 不存在的頁面,那么就會一下正常,一下 404 。其它 500 之類的錯誤也是類似的,這里也可以解決掉錯誤頁面出現(xiàn)的情況,后面學(xué)習(xí)代理模塊的錯誤處理時會說。 URI 和正則問題上面的配置是在 / 這個全局 URI 下配置的。如果是指定 URI ,比如這樣: 那么實際請求的后端服務(wù)地址是 http://192.168.56.88/aaa/ ,Proxy 模塊會自動拼接 URI 及請求 GET 參數(shù)。而如果我們在 proxy_pass 中指定了 URI ,則會直接使用 praxy_pass 的。 這個配置最終請求后端的地址是 http://192.168.56.89/a/ 。 而如果是正則,在上面的官方文檔中也說明了,正則,同時在 proxy_pass 也指定了 URI 的話,因為無法確定需要轉(zhuǎn)發(fā)的內(nèi)容,所以無法正常配置。 檢查或者重載配置,會報出一個錯誤信息。 那么要怎么處理呢?上面文檔也說了,必須要帶正則參數(shù)。比如這樣: 就可以正常通過了,如果只是普通正則,沒有 (.*) 內(nèi)容也沒事,只要帶上一個 $1 就行,沒有括號匹配內(nèi)容這個值就是空的。另外需要注意的是,這種形式代理轉(zhuǎn)發(fā)過來的,不會帶 GET 參數(shù),因此,可以這么寫: 現(xiàn)在嘗試訪問 http://192.168.56.88:8027/bbb/sdf?lksj 這個路徑,最終請求的代理服務(wù)器的路徑是 http://192.168.56.88/aaa/?lksj&/sdf 這樣的內(nèi)容。 配置一個正向代理說了半天反向代理,那么 Nginx 能做正向代理嗎?既然都寫在這里了,那肯定是可以的呀。 首先需要配置一個 resolver 也就是 DNS 解析服務(wù)器的地址,咱們就通用的 114 就好了。這個指令之前在基礎(chǔ)的 HTTP 核心模塊的學(xué)習(xí)中就學(xué)過,當(dāng)時也說過它是在做正向代理的時候需要用到的。原因嘛,因為正向代理,我們接收到的請求都是域名,需要有 DNS 解析到真實的 IP ,不像反向代理,是通過 Nginx 發(fā)送請求,這里請求是直接轉(zhuǎn)發(fā)的,沒有調(diào)用其它發(fā)送請求的函數(shù)。因此,需要有這個配置,如果不配置它的話,訪問會報出 502 錯誤,日志中會有如下記錄。 然后就是 proxy_pass 的配置。這里我們?nèi)慷际鞘褂米兞浚驗槲覀円L問的是用戶在客戶端輸入的網(wǎng)址,這些內(nèi)容需要通過變量獲取到。就像上面在概念中說的,正向代理要訪問誰,是用戶決定的,我們做代理時,要拿到用戶請求的網(wǎng)址信息。 接下來,通過瀏覽器進(jìn)行代理配置,所有瀏覽器都可以配置,這里我就直接拿 Postman 配置,在設(shè)置中打開下面的代理并填上代理服務(wù)器的 IP 地址和端口。
試著用配好代理的這個瀏覽器訪問一下百度吧,正常打開是不是?但是,查看 88 服務(wù)器上 Nginx 的 access_log 日志,你會發(fā)現(xiàn)這是通過我們的 Nginx 代理請求的。 使用 WireShark 抓包也能看出來。 總結(jié)今天的內(nèi)容很多都是概念,包括代理、正向代理、反向代理,還接觸到了一點負(fù)載均衡的概念。也說明了即使不用負(fù)載均衡,很多情況下我們也需要代理的原因。而真正學(xué)習(xí)到的配置指令就只有一個 proxy_pass 。是的,就這么簡單,一個代理服務(wù)器就配置完成了。不過僅有這個還不夠,整個代理模塊還有很多其它的配置選項,我們在后面還會一一學(xué)習(xí)。不過大家不用太擔(dān)心,因為我們已經(jīng)學(xué)習(xí)過 FastCGI 了,整個 Nginx 只要是帶 proxy 這個單詞的,不管是 FastCGI、SCGI還是UWSGI ,或是我們現(xiàn)在要學(xué)的普通代理,大部分配置指令都是相通的。因此,后面的學(xué)習(xí)還是比較輕松愉快的。不過還是強(qiáng)調(diào)一下,SCGI、UWSGI 這兩個模塊我們就不單獨講了哦,一是太像了,二是咱們 PHP 碼農(nóng)大部分情況下用不到,主攻 FastCGI 和 Proxy 就可以啦。 參考文檔: http:///en/docs/http/ngx_http_proxy_module.html |
|
|