Nginx功能篇25—结尾斜杠问题

概述

在 Nginx 的配置文件中,由于涉及到 URI 路径或者文件系统中的目录时,都会有结尾处 "/" 问题,这里来专门说明。

location 上下文中的结尾斜杠

location 上下文的结尾斜杠比较好理解,举例来说:

  • location /doc { ... } - 普通前缀匹配(无修饰符),由于 URL 路径没有末尾斜杠,则可以匹配以 "/doc" 开头的任意 URL,如:

    • /doc/index.html
    • /docs/index.html
    • /document/a.html
    • ...
  • location /docs/ { ... } - 普通前缀匹配(无修饰符),由于 URL 路径有末尾斜杠,则可以匹配以 "/docs/" 开头的任意 URL,如:

    • /docs/index.html
    • /docs/a.png
    • /docs/sub/b.js
    • ...
最佳实践
location 上下文中的路径尽量带上末尾的 "/",边界会更加清晰

目录别名中的结尾斜杠

若您使用了 Nginx 的别名功能,则需要:

  • 要实现该功能,您需要在 location 上下文中使用 alias 指令
  • 若 alias 指令后面的指令参数是一个目录,则强烈建议结尾处带有 "/" ,表明这是一个目录,如 alias /test/;
  • 若 location 上下文匹配的是目录资源,则 URL 路径在结尾处也应该带有 "/",如 location /images/ { ... }
  • 若使用了目录别名功能,则在对应的 location 上下文中通常都会使用 index 指令定义一个或多个索引文件,若索引文件不存在,Nginx 默认会提示 "403" 错误,除非开启了目录浏览(目录列表)功能

正确配置:location 上下文的 URL 路径与别名指令的指令参数都带有末尾 "/"

...
events {
    ...
}
...

http {
    ...
    server {
        ...
        location / {
            # 这里 root 指令的指令参数通常都建议在结尾处带上 "/"
            root   /html/games/;
            index  index.html index.htm;
        }

        # location 中 URI 的结尾必须带上 "/",因为在此 location 上下文中使用了 alias 指令
        location /images/ {
            # 使用了 alias 指令,指令参数的结尾必须带上 "/"
            # 浏览器请求 http://192.168.100.20/images/dogs.jpg 时,实际请求的是文件系统中的 /var/www/attachment/dogs.jpg
            alias /var/www/attachment/;
            autoindex off;
        }
    }
}

特殊情况:在 Nginx 中也允许 location 的 URL 路径与别名指令的指令参数末尾都不带 "/",但是不建议这样配置,容易出现路径错误问题。都不带末尾 "/" 仅出现在文件别名这种非常特殊的情况,如下所示

...
events {
    ...
}
...

http {
    ...
    server {
        ...
        location / {
            root   /html/games/;
            index  index.html index.htm;
        }

        # 精准前缀匹配
        location = /favicon.ico {
            alias /var/www/static/my-favicon.ico;
        }
    }
}
最佳实践
alias 指令的指令参数的结尾 "/" 与 location 上下文中的 URL 路径结尾 "/" 强烈建议成对出现

反向代理中的结尾斜杠

proxy_pass 指令用来设置后端服务器的协议(http 协议或 https 协议)和地址(IP 地址或域名),语法为 proxy_pass URL;

情况 A :proxy_pass 指令的指令参数不带结尾斜杠

若配置文件的内容是类似这样的:

...
events {
    ...
}
...

http {
    ...
    upstream backend1 {
        server 192.168.100.30 max_fails=3 fail_timeout=60s;
        server 192.168.100.35 max_fails=3 fail_timeout=60s;
        server 192.168.100.40 max_fails=3 fail_timeout=60s;
    }
    ...

    server {
        listen 192.168.100.20:80;
        server_name my-tests.com www.my-tests.com;

        return 301 https://www.my-tests.com$request_uri;
    }

    server {
        listen 192.168.100.20:443 ssl http2 backlog=8000 reuseport;
        server_name www.my-tests.com;

        # SSL/TLS 证书相关的配置
        ...

        # 其他相关的配置
        ...

        # location 上下文的 URL 结尾处带了 "/"
        location /images/ {
            # 指定上游服务器,这里的 URL 在结尾处没有带 "/"
            proxy_pass http://backend1;
            ...
        }
    }
}

此处,Nginx 代理服务器会保留 location 匹配的 URL 路径(以 "/images/" 开头的普通前缀匹配):

https://192.168.100.20/images/dogs.jpg ---> 浏览器请求地址

http://192.168.100.35/images/dogs.jpg ---> 实际可能的后端地址

说明
这种形式的配置在生产环境中最常见也最不容易出错。

情况 B :proxy_pass 指令的指令参数带结尾斜杠

若配置文件的内容是类似这样的:

...
events {
    ...
}
...

http {
    ...
    upstream backend1 {
        server 192.168.100.30 max_fails=3 fail_timeout=60s;
        server 192.168.100.35 max_fails=3 fail_timeout=60s;
        server 192.168.100.40 max_fails=3 fail_timeout=60s;
    }
    ...

    server {
        listen 192.168.100.20:80;
        server_name my-tests.com www.my-tests.com;

        return 301 https://www.my-tests.com$request_uri;
    }

    server {
        listen 192.168.100.20:443 ssl http2 backlog=8000 reuseport;
        server_name www.my-tests.com;

        # SSL/TLS 证书相关的配置
        ...

        # 其他相关的配置
        ...

        # location 上下文的 URL 结尾带了 "/"
        location /api/ {
            # 指定上游服务器,这里的 URL 在结尾处有带 "/"
            proxy_pass http://backend1/;
            ...
        }
    }
}

此处,Nginx 代理服务器会将 location 匹配的 URL 路径(以 "/api/" 开头的普通前缀匹配)替换为代理 URL 结尾处的 "/":

https://192.168.100.20/api/index.html ---> 浏览器请求地址

http://192.168.100.35/index.html ---> 实际可能的后端地址

情况 C :踩坑配置与修改

...

http {
    ...
    server {
        ...
        location /api/ {
            proxy_pass http://backend1/media;
        }
    }
}

此处,Nginx 代理服务器会将 location 匹配的 URL 路径(以 "/api/" 开头的普通前缀匹配)替换为代理 URL 结尾处的 "/media":

https://192.168.100.20/api/index.html ---> 浏览器请求地址

http://192.168.100.35/mediaindex.html ---> 实际可能的后端地址

若预期的后端地址是:

http://192.168.100.35/media/index.html

则需要修改成 proxy_pass http://backend1/media/;

最佳实践
当 Nginx 作为反向代理的代理服务器时,总结来说就是:
* 大多数情况下 location 上下文中的路径需要带末尾斜杠
* 对于代理的 URL 而言,大多数情况下不带末尾斜杠
* 若是子路径替换(上面情况 C 的修改),则 proxy_pass 指令的指令参数的结尾 "/" 与 location 上下文中的路径结尾 "/" 必须成对出现
Avatar photo

关于 陸風睿

GNU/Linux 从业者、开源爱好者、技术钻研者,撰写文档既是兴趣也是工作内容之一。Q - "281957576";WeChat - "jiulongxiaotianci",Github - https://github.com/jimcat8
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇