# nginx常见问题

# nginx location 加斜杠和不加斜杠

区别在于是否匹配子路径

# location /users

会匹配所有以 /users 开头的路径,但不会匹配/users本身,比如

#不会匹配
/users 
# 会匹配
/usersxxx
/users/
/users/xxx
1
2
3
4
5
6

# location /users/

会匹配所有以 /users/ 开头的路径,包括 /users/ 本身。例如,它会匹配/users/ 、/users/foo/、/users/bar/ ,不会匹配/usersxxx

#不会匹配
/users
/usersxxx
# 会匹配
/users/
/users/xxx
1
2
3
4
5
6

# root和alias的区别

location内写root

最终的文件路径是将 root 指定的路径与请求的 URI 拼接起来

server {
    root /var/www; # 全局 root

    location /app/ {
        root /opt/homebrew/var/reactrouter/dist;
    }
}
1
2
3
4
5
6
7
server {
    listen 30008;
    server_name localhost;
    # root /opt/homebrew/var/web;
    # 使用 root 指令
    location /images/ {
        root /opt/homebrew/var/web/;
    }
    # 使用 alias 指令
    location /pictures/ {
        alias /opt/homebrew/var/web/pictures/;
    }
    location / {
        try_files $uri $uri/ /index.html;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • 请求 http://localhost:30008/images/data.png,匹配 /images/,root会拼上 /images/data.png,将映射到 /opt/homebrew/var/web/images/data.png
  • 请求 http://localhost:30008/pictures/dora.png,匹配 /pictures/,alias会替换掉location的值,将映射到 /opt/homebrew/var/web/pictures/dora.png

# alias

如果将上面的alias调整为alias /opt/homebrew/var/web/pictures,不以 / 结尾,则返回404

==所以alias要以 / 结尾==

举例:

location /skybox-aicc-portal/ {
    root /Users/cheng/iFly/ZGH/zs-portal-zgh/;
    try_files $uri $uri/ /skybox-aicc-portal/index.html;
}
# 代理静态资源,防止 404
location /skybox-aicc-portal/ {
    alias /Users/cheng/iFly/ZGH/zs-portal-zgh/skybox-aicc-portal/;
}
1
2
3
4
5
6
7
8

这里两个配置效果相同

root 与 alias:当使用 root 时,Nginx 会将 URI 和 root 拼接起来。而使用 alias 时,Nginx 会将请求的路径替换成 alias 指定的目录,避免路径拼接错误。

# 最终访问的路径是/opt/homebrew/var/web/router/dist/app/
location /app/ {
    root /opt/homebrew/var/web/router/dist/;
    expires 1h;
    try_files $uri $uri/ /index.html;
}
1
2
3
4
5
6

在使用 alias 时,路径的实际解析会从 alias 开始替换,所以 try_files 的 $uri 会映射到 alias 的路径,而不是 root 的路径。

我们以这个配置为例

server {
  listen 20003;
  server_name localhost;
  root /opt/homebrew/var/web;

  location /vue-app/ {
    alias /opt/homebrew/var/web/vue-app/dist/;
    expires 1h;
    try_files $uri $uri/ /index.html;
    error_page 404 /index.html;
  }
1
2
3
4
5
6
7
8
9
10
11

在 location /vue-app/ 中,alias 会替换掉匹配的 location 前缀,因此:

  • 请求路径 /vue-app/home 实际会解析为 /opt/homebrew/var/web/vue-app/dist/home。
  • 请求路径 /vue-app/ 实际会解析为 /opt/homebrew/var/web/vue-app/dist/。

当使用 try_files $uri $uri/ /index.html 时:

  • $uri 是 /vue-app/home,因此会查找 /opt/homebrew/var/web/vue-app/dist/vue-app/home(无效)。
  • $uri/ 是 /vue-app/home/,因此会查找 /opt/homebrew/var/web/vue-app/dist/vue-app/home/(无效)。
  • 回退到 /index.html 时,它会解析为 /opt/homebrew/var/web/index.html,而不是期望的 /opt/homebrew/var/web/vue-app/dist/index.html。

**问题:**为什么/index.html指的是/opt/homebrew/var/web/index.html呢

  • 注意这里try_files 里的 绝对路径(以 / 开头)是基于 server 的 root,而不是 alias

  • 要让它回退到 alias 目录下的文件 → 用相对路径

# try_files $uri $uri/ /vue-app/index.html;中的/vue-app/指的是什么?

在 try_files $uri $uri/ /vue-app/index.html; 这行配置中,/vue-app/是指浏览器url中的路径还是指资源文件在服务器上的路径?

/vue-app/index.html 指的是 浏览器 URL 路径,而不是服务器上的实际文件路径。

如何理解try_files $uri $uri/ /vue-app/index.html;呢,即先找$uri,再找$uri/,找不到最终再查找/vue-app/index.html,也就是匹配/vue-app/规则

# alias带斜杠和不带斜杠

server {
    listen 80;
    server_name example.com;

    # 带斜杠的 alias
    location /pictures/ {
        alias /var/www/html/images/;
    }

    # 不带斜杠的 alias
    location /photos/ {
        alias /var/www/html/images;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 访问 http://example.com/pictures/picture.jpg 将映射到 /var/www/html/images/picture.jpg。
  • 访问 http://example.com/photos/picture.jpg 将映射到 /var/www/html/images/photos/picture.jpg。

# 解释

  • 带斜杠的 alias:只替换 location 匹配到的部分,不会添加额外的斜杠,路径直接连接。
  • 不带斜杠的 alias:在 alias 路径和请求的 URI 部分之间添加一个斜杠,结果是路径连接。

# return 和rewrite重定向

location / {
    return 301 /app/;
}

location / {
    rewrite ^/$ /app/ permanent;
}
1
2
3
4
5
6
7

return 301 和 rewrite 都可以实现重定向

return 301适用于简单的重定向,不需要进一步修改 URL 路径。

# 使用302 Location进行重定向

# 子路径部署(sub-path deploy)

location ^~ /vue-app/ {
        alias /Users/cheng/Github/Vue3/vue3-template/app/vue3-template/dist/;
        # # 自动添加末尾斜杠(可选)
        # rewrite ^/vue-app$ $scheme://$host$uri/ permanent;
        expires 1h;
        # # 优先尝试返回具体文件,找不到则返回 index.html
        try_files $uri $uri/ /vue-app/index.html;
        error_page 404 /vue-app/index.html;
    }
1
2
3
4
5
6
7
8
9

为什么try_files中是 /vue-app/index.html 而不是 /index.html

这是子路径部署(sub-path deploy)时常见的问题,因为你的 Vue 应用 不是部署在根路径 /,而是部署在:

/vue-app/,所以对应的 Nginx fallback(history 模式匹配不到时返回的文件)

必须匹配访问路径,而不是物理路径。

# return 301 /agent/ 和 return 301 $scheme://$host/agent/

location = /agent {
    return 301 /agent/;
}

location = /agent {
    return 301 $scheme://$host/agent/;
}
1
2
3
4
5
6
7

# 一、return 301 /agent/ 的行为

  • 只是返回一个相对路径重定向(Location: /agent/)
  • 浏览器会根据当前协议和主机自动补全
  • ✅ 对单域名场景一般没问题
  • ❌ 如果请求是 https://example.com:28082/agent,浏览器会自动补全,但端口可能没问题;但是在跨域或负载均衡、代理、反代场景下可能会出问题

# 二、return 301 $scheme://$host/agent/ 的行为

  • 明确协议 + 域名 + 端口,返回绝对 URL
  • 完全不会依赖浏览器自己补全
  • ✅ 无论你前端在 HTTP、HTTPS、或者 behind proxy、负载均衡器,都会100% 正确
  • ✅ SEO 更安全,搜索引擎喜欢绝对 URL
  • ✅ 可以避免 HTTPS / HTTP 自动切换问题

外部 Nginx 在 443 端口转发到内部 28082

Location 可能被浏览器认为是相对于内部端口(某些代理环境、Docker / Kubernetes 端口映射容易出现问题)

访问:443/agent可能会

这样还有个问题,会丢失查询参数

解决办法

# $args保留参数

return 301 $scheme://$host$uri/$is_args$args;
1
  • $args → 原始的 query string,例如 loginType=uap
  • $is_args → 如果 $args 非空则返回 ?,否则返回空

$is_args 和 $args 都是 Nginx 的内置变量

$args

  • 作用:表示请求的 query string(问号 ? 后面的部分)

$is_args

  • 作用:判断是否存在 query string,用于拼接问号 ?