亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

Nginx 的反向代理

Nginx 最強大的地方是在于其 HTTP 請求的反向代理,也即常說的七層反向代理。在這一層代理中,通過 Nginx 框架提供的相關配置,我們能在該層將發送過來的 http 協議轉換成各種其他的協議比如 fastcgi 協議、uwsgi協議、grpc、http(高版本協議)、websocket協議等。這樣使用 Nginx 框架,我們可以支持多種應用服務(java web、python web等)的反向代理。

Nginx 從1.9.0開始,新增加了一個 stream 模塊,用來實現四層協議( TCP 或 UDP 協議)的轉發、代理或者負載均衡。這層比較簡單,只是單純將 TCP 或 UDP 層的流量轉發到上游服務器中。接下來,我們將分別介紹這兩種反向代理的基本用法。

1. Nginx 的四層反向代理

前面我們剛開始使用 Nginx 時只是用了 http 指令塊,因為是針對 http 請求進行處理。這進行的是四層反向代理,轉發 TCP 或者 UDP 協議的報文。針對該層的處理,Nginx 是使用了 stream 模塊進行處理,對應的是 stream 指令塊,它和 http 指令塊非類似,用法幾乎一致。stream 指令塊里面可以包含 server 指令塊,server 指令塊里面也可以包含 listen 指令塊指定監聽的端口、還可以包含 proxy_pass
指令,對該端口監聽的 tcp 或者 udp 報文進行轉發。總之,和 http 指令塊大部分用法一致。

...

stream {
    ...
        
    server {
        listen 3440;
        # 轉發四層流量
        proxy_pass 192.168.1.103:3440;
    }
    
    ...
}

...

此外,從nginx-1.11.2版開始, ngx_stream_core_module,也同 http 模塊一樣支持變量,部分支持變量如下,這和 http 模塊也是類似的,甚至連變量名都非常相似:

$binary_remote_addr: 二進制格式的客戶端地址
$bytes_received: 從客戶端接收到的字節數
$bytes_sent: 發往客戶端的字節數
$hostname: 連接域名
$msec: 毫秒精度的當前時間
$nginx_version: nginx的版本
$pid: worker進程號
$protocol: 通信協議(UDP or TCP)
$remote_addr: 客戶端ip
$remote_port: 客戶端端口
$server_addr: 接受連接的服務器ip,計算此變量需要一次系統調用。所以避免系統調用,在listen指令里必須指定具體的服務器地址并且使用參數bind。
$server_port: 接受連接的服務器端口
$session_time: 毫秒精度的會話時間(版本1.11.4開始)
$status: 會話狀態(版本1.11.4開始), 可以是一下幾個值:
200
成功
400
不能正常解析客戶端數據
403
禁止訪問
500
服務器內部錯誤
502
網關錯誤,比如上游服務器無法連接
503
服務不可用,比如由于限制連接等措施導致
$time_iso8601: ISO 8601時間格式
$time_local: 普通日志格式的時間戳

2. Nginx 七層反向代理

2.1 http協議的反向代理

nginx 七層方向代理處理的是 http 請求,對應的是 http 協議。如果只是轉發 http 請求,可以簡單使用 proxy_pass 指令即可。這和我們之前簡單的反向代理示例一致。

# 在轉發 http 請求時,URL必須以 http 或者 https 開頭 
Syntax:	proxy_pass URL;
Default:Context: location, if in location, limit_except

在使用 prxoy_pass 指令對 http 或者 https 協議進行反向代理時,需要注意一下問題:

  • 在 URL 不攜帶 URI 時,會將對應的 URL 直接轉發到上游服務器
  • 在 URL 攜帶 URI 時,會將 location 參數中匹配上的那一段替換為該URL

看下面的示例配置:


...

http {
    
    server {
        listen 8000;
        location /test {
            proxy_pass http://ip:port/xyz;
        }
    }
    
    server {
        listen 9000;
        location /test {
            proxy_pass http://ip:port;
        }
    }
    
}

... 

在代理 http 請求 http://主機ip:8000/test/abc 時,由于 proxy_pass 指令后面的 URL 帶了 /xyz 這樣的路徑,所以轉發的請求是 http:// ip:port/xyz/abc,其中匹配的 /test 已經被替換掉了。而對于第二個 http 請求 http://主機ip:9000/test/abc 時,由于 proxy_pass指令后面直接是上游服務器地址,沒有帶 URI,所以轉發的請求為 http://ip:port/test/abc,其中匹配到的/test并沒有被替換。

3. 案例實戰

本節實戰中,我們準備好兩個案例測試,一個是測試使用 stream 模塊進行四層方向代理測試;另一個案例測試前面提到的七層代理中 proxy_pass 指令的用法,主要實戰前面提到的注意點。

3.1 四層反向代理示例

在nginx.conf的中加入如下配置:

...
stream {
    server {
        listen 3000;
        return '3000 server get ip: $remote_addr!\n';
    }
    
    server {
        listen 30;
        # 注意,只寫ip和port,不要加上[http:]之類的,這里是四層的協議
        proxy_pass 127.0.0.1:3000;
    }

}
...

啟動 nginx 后,我們在外面通過 telnet 命令訪問該主機的 3000 和 30端口,可以看到如下結果:

[shen@shen ~]$ telnet 180.76.152.113 3000
Trying 180.76.152.113...
Connected to 180.76.152.113.
Escape character is '^]'.
3000 server get ip: 103.46.244.108!

[shen@shen ~]$ telnet 180.76.152.113 30
Trying 180.76.152.113...
Connected to 180.76.152.113.
Escape character is '^]'.
3000 server get ip: 127.0.0.1!
Connection closed by foreign host.

可以看到,訪問30端口時,nginx 幫我們轉發 tcp 層流量到 3000端口,最后返回了相關響應字符串。

3.2 七層反向代理示例

在 nginx.conf 中加入如下的測配置:

...

http {
    
    server {
        listen   8000;
        return   200  '$uri\n';
    }

    server {
        listen   9001;
        location /test {
            proxy_pass http://127.0.0.1;
        }
    }


    server {
        listen   9002;
        location /test {
            proxy_pass http://127.0.0.1/xyz;
        }
    }

}

...

啟動 nginx 后,通過請求服務器的8000端口,我們可以知道請求的 uri 值,然后測試經過兩種類型的 proxy_pass 配置后最后的 uri 的值。具體操作以及結果如下:

# 測試8000端口顯示的uri值
[shen@shen ~]$ curl http://180.76.152.113:8000/test/abc
/test/abc
# 9001端口配置中proxy_pass后面的URL不帶URI
[shen@shen ~]$ curl http://180.76.152.113:9001/test/abc
/test/abc
# 9002端口配置中proxy_pass后面的URL帶URI,會替換到匹配的/test
[shen@shen ~]$ curl http://180.76.152.113:9002/test/abc
/xyz/abc

4. 小結

本節中介紹了 Nginx 的四層反向代理和七層反向代理,并用案例進行了演示。剛開始使用時只是用了 http 指令塊,因為是針對 http 請求進行處理。這進行的是四層反向代理。nginx 七層方向代理處理的是 http 請求,對應的是 http 協議。如果只是轉發 http 請求,可以簡單使用 proxy_pass 指令即可。這和我們之前簡單的反向代理示例一致。