天天看點

Nginx常用反向代理配置規則nginx常用代理配置往期文章

nginx常用代理配置

因為業務系統需求,需要對web服務作nginx代理,在不斷的嘗試過程中,簡單總結了一下常見的nginx代理配置。

1. 最簡反向代理配置

在http節點下,使用upstream配置服務位址,使用server的location配置代理映射。

upstream my_server {                                                         
    server 10.0.0.2:8080;                                                
    keepalive 2000;
}
server {
    listen       80;                                                         
    server_name  10.0.0.1;                                               
    client_max_body_size 1024M;

    location /my/ {
        proxy_pass http://my_server/;
        proxy_set_header Host $host:$server_port;
    }
}           

通過該配置,通路nginx位址

http://10.0.0.1:80/my的請求會被轉發到my_server服務位址http://10.0.0.2:8080/。

需要注意的是,如果按照如下配置:

upstream my_server {                                                         
    server 10.0.0.2:8080;                                                
    keepalive 2000;
}
server {
    listen       80;                                                         
    server_name  10.0.0.1;                                               
    client_max_body_size 1024M;

    location /my/ {
        proxy_pass http://my_server;
        proxy_set_header Host $host:$server_port;
    }
}           

那麼,通路nginx位址

http://10.0.0.1:80/my的請求會被轉發到my_server服務位址http://10.0.0.2:8080/my。這是因為proxy_pass參數中如果不包含url的路徑,則會将location的pattern識别的路徑作為絕對路徑。

2. 重定向封包代理

即便配置了nginx代理,當服務傳回重定向封包時(http code為301或302),會将重定向的目标url位址放入http response封包的header的location字段内。使用者浏覽器收到重定向封包時,會解析出該字段并作跳轉。此時新的請求封包将直接發送給服務位址,而非nginx位址。為了能讓nginx攔截此類請求,必須修改重定向封包的location資訊。

location /my/ {
    proxy_pass http://my_server;
    proxy_set_header Host $host:$server_port;

    proxy_redirect / /my/;
}           

使用proxy_redirect可以修改重定向封包的location字段,例子中會将所有的根路徑下的url代理到nginx的/my/路徑下傳回給使用者。比如服務傳回的重定向封包的location原始值為/login,那麼經過nginx代理後,使用者收到的封包的location字段為/my/login。此時,浏覽器将會跳轉到nginx的/my/login位址進行通路。

需要注意的是,服務傳回的重定向封包的location字段有時會填寫絕對路徑(包含服務的ip/域名和端口),有時候會填寫相對路徑,此時需要根據實際情況進行甄别。

location /my/ {
    proxy_pass http://my_server;
    proxy_set_header Host $host:$server_port;

    proxy_redirect http://my_server/ http://$host:$server_port/my/;
}           

上述配置便是将my_server服務的根路徑下的所有路徑代理到nginx位址的/my/路徑下。當nginx配置隻有一個server時,

http://$host:$server_port

字首可以省略。

3. 封包資料替換

使用nginx代理最牛(dan)逼(sui)的情況就是http響應封包内寫死了服務位址或web絕對路徑。寫死服務位址的情況比較少見,但也偶爾存在。最棘手的是寫死了web絕對路徑,尤其是絕對路徑都沒有公共字首。舉個例子來說:

一般的web頁面會包含如下類似路徑:

  • /public:用于靜态頁面資源,如js腳本/public/js,樣式表/public/css,圖檔/public/img等。
  • /static:和/public類似。
  • /api:用于背景服務API接口。
  • /login:用于登入驗證。
  • 其他。

對于這樣的服務,可能的代理配置如下:

location /my/ {
    proxy_pass http://my_server/;
    proxy_set_header Host $host:$server_port;

    proxy_redirect / /my/;
}
location /login/ {
    proxy_pass http://my_server/public;
    proxy_set_header Host $host:$server_port;
}
location /public/ {
    proxy_pass http://my_server/public;
    proxy_set_header Host $host:$server_port;
}
location /api/ {
    proxy_pass http://my_server/api;
    proxy_set_header Host $host:$server_port;
}           

由于web頁面或靜态資源内寫死了類似的絕對路徑,那麼對于使用者來說,通過頁面内的連結進行跳轉時,都會請求到nginx服務對應的路徑上。一旦存在另一個服務也包含類似的路徑,也需要nginx進行代理,那麼沖突就出現了:通路nginx的同一個路徑下的請求究竟轉發給哪一個服務?

要解決這個問題,必須在使用者收到封包前,将封包的資料中包含的絕對路徑都添加統一的字首,如/my/public,/my/api,/my/login,這樣nginx代理配置則可以簡化為:

location /my/ {
    proxy_pass http://my_server/;
    proxy_set_header Host $host:$server_port;

    proxy_redirect / /my/;
}
location /other/ {
    proxy_pass http://other_server/;
    proxy_set_header Host $host:$server_port;

    proxy_redirect / /other/;
}           

nginx的ngx_http_sub_module子產品提供了類似的封包資料替換功能,該子產品預設不會安裝,需要在編譯nginx時添加--with-http_sub_module參數,或者直接下載下傳nginx的

rpm

包。

使用sub_filter對資料包進行替換的文法如下:

location /my/ {
    proxy_pass http://my_server/;
    proxy_set_header Host $host:$server_port;
    
    sub_filter 'href="/' 'href="/my/';
    sub_filter 'src="/' 'src="/my/';
    sub_filter_types text/html;
    sub_filter_once  off;
}           

上述配置會将/my/下的所有響應封包内容的href="/替換為href="/my,以及src="/替換為src="/my,即為所有的絕對路徑添加公共字首。

注意,如果需要配置多個sub_filter,必須保證nginx是

1.9.4版本

之上的。

4. 總結

即便如此,sub_filter也不能解決所有問題。目前流行的js架構都會有自動渲染url的功能,也就是說,很多絕對路徑并非寫死在靜态頁面内,也是由js代碼架構動态生成的,面對這樣的情況,sub_filter也是無能為力了。對于這樣的情況,筆者隻能由衷地奉勸,還是安靜的改代碼吧!

往期文章

Nginx系列教程(1)nginx基本介紹和安裝入門 Nginx系列教程(2)nginx搭建靜态資源web伺服器 Nginx系列教程(3)nginx緩存伺服器上的靜态檔案 Nginx系列教程(4)nginx處理web應用負載均衡問題以保證高并發 Nginx系列教程(5)如何保障nginx的高可用性(keepalived) Nginx系列教程(6)nginx location 比對規則詳細解說 Nginx系列教程 (7) nginx rewrite配置規則詳細說明 Nginx系列教程(8)nginx配置安全證書SSL Nginx系列教程(9)nginx 解決session一緻性

繼續閱讀