Nginx proxy_pass 指令详解

proxy_pass 指令简介

proxy_passngx_http_proxy_module的一个指令,用来指定代理服务器的协议, 地址,和可选的uri。

  • 协议分为http,https。
  • 地址可以是域名或者是ip地址,  也可以单独为协议指定端口。
proxy_pass http://example.com/uri

根据nginx的文档,proxy_pass指令有几点需要注意的地方:

  • 如果域名可以解析到多个ip地址,nginx会将这些ip通过round_robin算法来进行均衡。除此之外,地址项也可以是upstream模块定义的server_group。
  • proxy_pass的参数可以是变量(也可以包含变量),域名(即地址项) nginx会优先在定义的upstream中查找,如果没有找到,就会通过resolver去解析。

请求的uri传给后台的代理服务器时,会有以下几种方式:

  • 如果proxy_pass指令指定了uri,那一个请求到达的时候,原始uri中匹配的部分,会被proxy_pass中指定的uri替代。
# 浏览器中访问 /name/demo 时,代理服务器收到的请求是 /remote/demo
# /name/ 被 /remote/ 替换
location /name/ {
    proxy_pass http://127.0.0.1/remote/;
}
  • 如果proxy_pass的参数中没有指定uri,那uri会原封不动的从原始uri传递到被代理服务器。
# 浏览器访问 /some/path/demo 时,代理服务器收到的请求是 /some/path/demo
# 原封不动
location /some/path {
    proxy_pass http://127.0.0.1;
}

另一些情况,原始uri被替换的部分是不确定的。

  • 当location的匹配规则用到了正则表达式,然后在一个命名location中,这种情况,proxy_pass不能指定uri。
  • 当一个uri在一个代理location中(proxy_pass)使用rewrite指令改变了,你需要用break来继续这个请求。
# 浏览器访问 /name/demo 时,代理服务器收到的请求是 /users?name=demo
# rewrite会改写url,同时break告诉nginx不再进行location的匹配
location /name/ {
    rewrite    /name/([^/]+) /users?name=$1 break;
    proxy_pass http://127.0.0.1;
}
  • proxy_pass参数用到了变量时:
# 浏览器访问 /name/demo?name=123 时,代理服务器收到的请求是 /name/demo?name=123
location /name/ {
    proxy_pass http://127.0.0.1$request_uri;
}

在这种情况下,如果参数中包含了uri,他就会原样的传递到被代理服务器,替换原始请求中的uri。

Talk is cheap, show me the code!

# nginx.conf
# 我习惯用openresty实践,nginx算openresty的严格子集。openresty基于nginx,并且提供了一些额外的模块。
# 1. 新建工作目录,并切换到工作目录
# 2. mkdir logs
# 3. 将内容复制到nginx.conf,以下命令工作在bash下
# 启动: openresty -p `pwd` -c nginx.conf
# 重载: openresty -s reload -p `pwd` -c nginx.conf
# 停止: openresty -s stop -p `pwd` -c nginx.conf

events {
    worker_connections 1024;
}
worker_processes 1;
http {
    server {
        listen 8080;
        location / {
            # 普遍操作 Case 1:
            proxy_pass http://127.0.0.1:8081;
            echo_after_body "origin_request_uri: $request_uri";
            echo_after_body "origin_uri:         $uri";
            echo_after_body "origin_args:        $args";
        }
        
        location /some/path {
            # 普遍操作 Case 2:
            proxy_pass http://127.0.0.1:8081;
            echo_after_body "origin_request_uri: $request_uri";
            echo_after_body "origin_uri:         $uri";
            echo_after_body "origin_args:        $args";
        }
        
        # location的匹配串没有带反斜杆
        location /name1 {
            # Case 3: proxy_pass中包含uri,不包含尾部的反斜杆
            proxy_pass http://127.0.0.1:8081/remote;
            # Case 4: proxy_pass中包含uri, 包含尾部的反斜杠
            # proxy_pass http://127.0.0.1:8081/remote/;
            echo_after_body "origin_request_uri: $request_uri";
            echo_after_body "origin_uri:         $uri";
            echo_after_body "origin_args:        $args";
        }
        
        # location的匹配串带上了反斜杠
        location /name2/ {
            # Case 5: proxy_pass中包含uri,不包含尾部的反斜杠
            # proxy_pass http://127.0.0.1:8081/remote;
            # Case 6: proxy_pass中包含uri,包含尾部的反斜杠
            proxy_pass http://127.0.0.1:8081/remote/;
            echo_after_body "origin_request_uri: $request_uri";
            echo_after_body "origin_uri:         $uri";
            echo_after_body "origin_args:        $args";
        }
        location /rewrite {
            # Case 7: rewrite 重写请求的url
            rewrite    /rewrite/([^/]+) /users?name=$1 break;
            proxy_pass http://127.0.0.1:8081;
            echo_after_body "origin_request_uri: $request_uri";
            echo_after_body "origin_uri:         $uri";
            echo_after_body "origin_args:        $args";
        }
    }
    
    server {
        listen 8081;
        location / {
            echo "backend_request_uri:    $request_uri";
            echo "backend_uri:            $uri";
            echo "backend_args:           $args";
        }
    }
}

Case 1:

location / {
    # 普遍操作 Case 1:
    proxy_pass http://127.0.0.1:8081;
    echo_after_body "origin_request_uri: $request_uri";
    echo_after_body "origin_uri:         $uri";
    echo_after_body "origin_args:        $args";
}
luvjoey@luvjoey-pc ~/P/nginx-tutorial> curl localhost:8080/
backend_request_uri:    /
backend_uri:            /
backend_args:           
origin_request_uri: /
origin_uri:         /
origin_args:   

Case 2:

location /some/path {
    # 普遍操作 Case 2:
    proxy_pass http://127.0.0.1:8081;
    echo_after_body "origin_request_uri: $request_uri";
    echo_after_body "origin_uri:         $uri";
    echo_after_body "origin_args:        $args";
}
luvjoey@luvjoey-pc ~/P/nginx-tutorial> curl localhost:8080/hello/world
backend_request_uri:    /hello/world
backend_uri:            /hello/world
backend_args:           
origin_request_uri: /hello/world
origin_uri:         /hello/world
origin_args: 

Case 3, 4:

# location的匹配串没有带反斜杆
location /name1 {
    # Case 3: proxy_pass中包含uri,不包含尾部的反斜杆
    proxy_pass http://127.0.0.1:8081/remote;
    # Case 4: proxy_pass中包含uri, 包含尾部的反斜杠
    # proxy_pass http://127.0.0.1:8081/remote/;
    echo_after_body "origin_request_uri: $request_uri";
    echo_after_body "origin_uri:         $uri";
    echo_after_body "origin_args:        $args";
}
# Case 3:
luvjoey@luvjoey-pc ~/P/nginx-tutorial> curl localhost:8080/name1/hello/world
backend_request_uri:    /remote/hello/world
backend_uri:            /remote/hello/world
backend_args:           
origin_request_uri: /name1/hello/world
origin_uri:         /name1/hello/world
origin_args:   
# Case 4:
luvjoey@luvjoey-pc ~/P/nginx-tutorial> curl localhost:8080/name1/hello/world
backend_request_uri:    /remote//hello/world
backend_uri:            /remote/hello/world
backend_args:           
origin_request_uri: /name1/hello/world
origin_uri:         /name1/hello/world
origin_args:  

Case 5, 6

# location的匹配串带上了反斜杠
location /name2/ {
    # Case 5: proxy_pass中包含uri,不包含尾部的反斜杠
    # proxy_pass http://127.0.0.1:8081/remote;
    # Case 6: proxy_pass中包含uri,包含尾部的反斜杠
    proxy_pass http://127.0.0.1:8081/remote/;
    echo_after_body "origin_request_uri: $request_uri";
    echo_after_body "origin_uri:         $uri";
    echo_after_body "origin_args:        $args";
}
# Case 5:
luvjoey@luvjoey-pc ~/P/nginx-tutorial> curl localhost:8080/name2/hello/world
backend_request_uri:    /remotehello/world
backend_uri:            /remotehello/world
backend_args:           
origin_request_uri: /name2/hello/world
origin_uri:         /name2/hello/world
origin_args: 
# Case 6:
luvjoey@luvjoey-pc ~/P/nginx-tutorial> curl localhost:8080/name2/hello/world
backend_request_uri:    /remote/hello/world
backend_uri:            /remote/hello/world
backend_args:           
origin_request_uri: /name2/hello/world
origin_uri:         /name2/hello/world
origin_args:

Case 7:

location /rewrite {
    # Case 7: rewrite 重写请求的url
    rewrite    /rewrite/([^/]+) /users?name=$1 break;
    proxy_pass http://127.0.0.1:8081;
    echo_after_body "origin_request_uri: $request_uri";
    echo_after_body "origin_uri:         $uri";
    echo_after_body "origin_args:        $args";
}
luvjoey@luvjoey-pc ~/P/nginx-tutorial> curl localhost:8080/rewrite/helloworld
backend_request_uri:    /users?name=helloworld
backend_uri:            /users
backend_args:           name=helloworld
origin_request_uri: /rewrite/helloworld
origin_uri:         /users
origin_args:        name=helloworld

展示评论