# nginx常见问题
# nginx location 加斜杠和不加斜杠
区别在于是否匹配子路径
# location /users
会匹配所有以 /users 开头的路径,但不会匹配/users本身,比如
#不会匹配
/users
# 会匹配
/usersxxx
/users/
/users/xxx
2
3
4
5
6
# location /users/
会匹配所有以 /users/ 开头的路径,包括 /users/ 本身。例如,它会匹配/users/ 、/users/foo/、/users/bar/ ,不会匹配/usersxxx
#不会匹配
/users
/usersxxx
# 会匹配
/users/
/users/xxx
2
3
4
5
6
# root和alias的区别
location内写root
最终的文件路径是将 root 指定的路径与请求的 URI 拼接起来
server {
root /var/www; # 全局 root
location /app/ {
root /opt/homebrew/var/reactrouter/dist;
}
}
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;
}
}
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/;
}
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;
}
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;
}
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;
}
}
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;
}
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;
}
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/;
}
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;
$args→ 原始的 query string,例如loginType=uap$is_args→ 如果$args非空则返回?,否则返回空
$is_args 和 $args 都是 Nginx 的内置变量
$args
- 作用:表示请求的 query string(问号
?后面的部分)
$is_args
- 作用:判断是否存在 query string,用于拼接问号
?