Nginx代理:掌握proxy_pass的正确姿势

Nginx介绍

Nginx是一款高性能的HTTP和反向代理服务器,以其稳定性、丰富的功能集、简单的配置文件以及低资源占用而闻名。


Nginx的主要应用场景包括:

静态资源服务器:

        Nginx可以高效地提供静态文件,如HTML、CSS和JavaScript文件。

反向代理:

        Nginx可以作为前端代理,将客户端的请求转发到后端的服务器,并将后端服务器的响应返回给客户端。

        在Nginx的反向代理配置中,一个看似不起眼的字符可能会对请求的转发路径产生重大影响。本文将探讨代理地址设置中的几种情况及其对应的行为。

Nginx中如何配置反向代理

        Nginx能够作为一个反向代理来终结来自于客户端的请求,并且向上游服务器打开一个新的请求。

        在nginx中这个功能需要使用location指令来实现。

        location指令可以用在虚拟服务器server部分,并且意味着提供来自客户端的URI或者内部重定向访问。除少数情况外,location也可以被嵌套使用,它们被作为特定的配置尽可能地处理请求。

location定义如下:

location [modifier] uri {...}

 modifier会影响location的处理及优先级。

或者是命名location:

location @name {...}

        命名location仅对内部访问重定向,在进入一个location之前它会保留被请求的URI部分。命名location只能够在server级别定义。

location修饰符及处理方式:
  1.   =        使用精确匹配并且终止搜索。即一旦匹配上使用=修饰的location,下面的其它location配置就无效了。

  2.   ~        区分大小写的正则表达式匹配。

  3.   ~*       不区分大小写的正则表达式匹配。

  4.   ^~       如果该location是最佳的匹配,那么对于匹配这个location的字符串不再进行正则表达式检测。注意,这不是一个正则表达式匹配----它的目的是优先于正则表达式匹配

        当使用^~修饰符时,即使有其他更精确的匹配,也会选择这个location块。在这种情况下,即使有其他匹配规则,URI也不会被替换。

易错点澄清:何时替换uri?

        为了更好地响应客户端请求,可以根据请求的URI、http客户端参数或者一些约定的逻辑进行拆分。通过代理服务器,请求的原始URL中的任何部分都能够以这种方式进行转换。

        其中,把请求代理到上游服务器配置中,最重要的是proxy_pass指令。该指令用来设置被代理服务器的地址,可以是主机名称、IP地址加端口号等形式。

其语法结构为:

proxy_pass URL;

        其中,URL为要设置的被代理服务器的地址,包含传输协议、主机名称或IP地址+端口、URI等要素。传输协议通常是http或https。指令同时还接受以unix开始的UNIX-domain套接字路径。例如:

proxy_pass http://127.0.0.1:8080;
proxy_pass https://www.ai-as.net/newUri;
proxy_pass http://unix:/tmp/aias.socket:/uri/;

        明白了proxy_pass指令的使用,我们来解释大家经常讨论的一个问题,就是proxy_pass指令的URL变量末尾是否加斜杠“/”的问题。

先说结论:

如果proxy_pass后面的URL包含URI,带有URI部分的proxy_pass指令将会使用该URI替代request_uri中与location 指令uri相同的部分。后面示例有详细说明。

URL中没有包含URI的指定示例:location /uri {    proxy_pass http://www.ai-as.net;}其它情况在nginx看来,proxy_pass后面的URL都包含了URI,即使只加了一个斜杠“/”,即斜杠“/”也是URI。

例如,下面例子中的/uri,在请求传递到上游服务器时将会被替换为newUri

location /uri {    proxy_pass http://www.ai-as.net/newUri ;}

        以nginx/1.26.0为例,proxy_pass中URL有四种情况,nginx收到请求后,重新发起请求的URL如下图所示:

场景1:proxy_pass http://www.ai-as.net;

1.1浏览器请求的URL:
http://127.0.0.1/proxy_pass_no_dir_without_slash/

1.2Nginx中的conf/nginx.conf中的配置:

location /proxy_pass_no_dir_without_slash/ {   proxy_pass http://www.ai-as.net ;}

1.3Nginx重新发起请求的URL: 
http://www.ai-as.net/proxy_pass_no_dir_without_slash

原因:proxy_pass的URL http://www.ai-as.net上没有包含资源路径URI

1.4示例:

% curl http://127.0.0.1/proxy_pass_no_dir_without_slash/

nginx debug日志:

场景2:proxy_pass http://www.ai-as.net/;

2.1浏览器请求的URL:
http://127.0.0.1/proxy_pass_no_dir_with_slash/

2.2Nginx中的conf/nginx.conf中的配置:

location /proxy_pass_no_dir_with_slash/ {    proxy_pass http://www.ai-as.net/ ;}

2.3Nginx重新发起请求的URL:
http://www.ai-as.net/

原因:proxy_pass的URL http://www.ai-as.net上包含资源路径“/”。

2.4示例:

curl http://127.0.0.1/proxy_pass_no_dir_with_slash/

nginx debug日志:

场景3:proxy_pass http://www.ai-as.net/dir;

3.1浏览器请求的URL:
http://127.0.0.1/proxy_pass_dir_without_slash/

3.2Nginx中的conf/nginx.conf中的配置:

location /proxy_pass_dir_without_slash/ {   proxy_pass http://www.ai-as.net/dir;}

3.3Nginx重新发起请求的URL:
http://www.ai-as.net/dir

原因:proxy_pass的URL http://www.ai-as.net上包含资源路径“/dir”。

3.4示例:

curl http://127.0.0.1/proxy_pass_dir_without_slash/

nginx debug日志:

场景4:proxy_pass http://www.ai-as.net/dir/ ;

4.1浏览器请求的URL:
http://127.0.0.1/proxy_pass_dir_with_slash/

4.2Nginx中的conf/nginx.conf中的配置:

location /proxy_pass_dir_with_slash/ {    proxy_pass http://www.ai-as.net/dir/ ;}

4.3Nginx重新发起请求的URL:
http://www.ai-as.net/dir/

原因:proxy_pass的URL http://www.ai-as.net上包含资源路径“/dir/ ”。

4.4示例:

% curl http://127.0.0.1/proxy_pass_dir_with_slash/

nginx debug日志:

5、使用到的nginx/nginx.con

% cat conf/nginx.conf

#user  nobody;
worker_processes  1;
error_log  logs/error.log  debug;

#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        location /proxy_pass_no_dir_without_slash/ {
            proxy_pass http://www.ai-as.net ;
        }

        location /proxy_pass_no_dir_with_slash/ {
            proxy_pass http://www.ai-as.net/ ;
        }

        location /proxy_pass_dir_without_slash/ {
            proxy_pass http://www.ai-as.net/dir;
        }

        location /proxy_pass_dir_with_slash/ {
            proxy_pass http://www.ai-as.net/dir/ ;
        }

        # error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
}
​​​​

查看的日志文件:logs/error.log

% tail -f logs/error.log2024/05/31 17:23:59 [debug] 66640#0: *38 http keepalive handler
2024/05/31 17:23:59 [info] 66640#0: *38 kevent() reported that client 127.0.0.1 closed keepalive connection
2024/05/31 17:23:59 [debug] 66640#0: *38 close http connection: 4
2024/05/31 17:23:59 [debug] 66640#0: *38 event timer del: 4: 13660789921
2024/05/31 17:23:59 [debug] 66640#0: *38 reusable connection: 0
2024/05/31 17:23:59 [debug] 66640#0: *38 free: 0000000000000000
2024/05/31 17:23:59 [debug] 66640#0: *38 free: 00007FD0E8105850, unused: 152
2024/05/31 17:23:59 [debug] 66640#0: timer delta: 1
2024/05/31 17:23:59 [debug] 66640#0: worker cycle
2024/05/31 17:23:59 [debug] 66640#0: kevent timer: -1, changes: 0

小结

        Nginx作为一款功能强大的反向代理服务器,其location和proxy_pass指令提供了灵活的配置选项。然而,在使用过程中,需要注意一些易错点,如proxy_pass中的斜杠问题、多次重写以及特殊场景下的URI不替换。通过仔细检查和理解这些细节,可以避免常见的配置错误,确保Nginx正确地转发请求。

  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

missterzy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值