前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Nginx代理:掌握proxy_pass的正确姿势

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

作者头像
烟雨平生
发布2024-05-27 16:27:48
1.6K0
发布2024-05-27 16:27:48
举报
文章被收录于专栏:数字化之路数字化之路

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

  1. 静态资源服务器:Nginx可以高效地提供静态文件,如HTML、CSS和JavaScript文件。
  2. 反向代理:Nginx可以作为前端代理,将客户端的请求转发到后端的服务器,并将后端服务器的响应返回给客户端。

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

Nginx中如何配置反向代理

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

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

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

location定义如下:

代码语言:javascript
复制
location [modifier] uri {...}

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

或者是命名location:

代码语言:javascript
复制
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地址加端口号等形式。

其语法结构为:

代码语言:javascript
复制
proxy_pass URL;

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

代码语言:javascript
复制
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变量末尾是否加斜杠“/”的问题。

先说结论:

代码语言:javascript
复制
如果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

代码语言:javascript
复制
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中的配置:

代码语言:javascript
复制
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示例:

代码语言:javascript
复制
% 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中的配置:

代码语言:javascript
复制
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示例:

代码语言:javascript
复制
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中的配置:

代码语言:javascript
复制
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示例:

代码语言:javascript
复制
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中的配置:

代码语言:javascript
复制
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示例:

代码语言:javascript
复制
% curl http://127.0.0.1/proxy_pass_dir_with_slash/

nginx debug日志:

5、使用到的nginx/nginx.conf

代码语言:javascript
复制
% 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

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

留个小问题: 你的nginx error.log日志中示例中的debug日志吗?

小结

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

巩固小作业

下面的这个location配置效果是一致的吗? 配置1:

代码语言:javascript
复制
location / {
    proxy_pass http://www.ai-as.net;
}

配置2:

代码语言:javascript
复制
location / {
    proxy_pass http://www.ai-as.net/;
}

REFERENCE

https://www.bilibili.com/video/BV1GJ4m187Em/?vd_source=028ee6e6a7217b4a4237d439b7fd348d

通过debug日志定位问题 https://time.geekbang.org/course/detail/100020301-79641

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 的数字化之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Nginx中如何配置反向代理
  • 易错点澄清:何时替换uri?
  • 小结
  • 巩固小作业
  • REFERENCE
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档