Nginx二级子路径请求,如何去掉尾部多余的"/"以及避免301重定向请求
本文主要是讨论访问页面url触发了多余的重定向,以及末尾多了 / 问题。本文讨论的问题主要是使用 try_files 引起的问题,虽最终解决的方案并未去做 absolute_redirect 相关的配置修改,但实则也是与 absolute_redirect 相关。在本文也会主要对 try_files 和 absolute_redirect 相关的参数配置进行说明。
问题背景
昨天在React项目中,通过代理的方式,从本地代理指向到开发环境域名下的一个二级目录部署的项目,发现通过本地地址访问一直无法正常。查看网络请求,发现代理的 URL 链接触发了 301 重定向,导致跳到了原来的域名下。
先看下出问题现象(其实也不算是问题,这是nginx的正常机制,请往下看):

1、我访问的URL是:https://op-dev.xxxxxx.cn/osp
2、301 重定向到了 http://op-dev.xxxxx.cn/osp/
3、302 重定向到了 https://op-dev.xxxxxx.cn/osp/ (这个302其实是因为我们设置了强制https,所以又从http跳回了https)
通过上图,我的主要疑惑有2个:
- 为什么会在url的路径后面会自动拼接上
/ - 我明明访问的是
https地址, 为什么会重定向到http地址上
解决问题
先贴下原本的nginx二级目录的配置
location ^~ /osp {
alias /data/www/osp/build;
index index.html;
try_files $uri $uri/ /osp/index.html;
}
先说解决办法:
1、最根本的问题是因为触发了nginx的301重定向导致,只要避免触发重定向即可。如果你能忍受直接使用如 https://op-dev.xxxxxx.cn/osp/ 这样最后带/的地址,那也就没我们上面的问题了
2、如果你跟我一样有点代码小洁癖,一定无法忍受,请看下面:
location ^~ /osp {
alias /data/www/osp/build;
index index.html;
# 请看这里,原本 `$uri/` 改成 `$uri/index.html`
try_files $uri $uri/index.html /osp/index.html;
}
这里其实对try_files的参数配置,很简单的一个改动,一直没有太在意。(到此,结束了吗? 我们并未真正知晓为什么 https 会重定向到 http 地址上, 请继续往下看吧。)
try_files 的使用
官方文档说明:http://nginx.org/en/docs/http/ngx_http_core_module.html#try_files
| Syntax: | try_files file ... uri; try_files file ... =code; |
|---|---|
| Default: | — |
| Context: | server, location |
Checks the existence of files in the specified order and uses the first found file for request processing; the processing is performed in the current context. The path to a file is constructed from the file parameter according to the root and alias directives. It is possible to check directory’s existence by specifying a slash at the end of a name, e.g. “$uri/”. If none of the files were found, an internal redirect to the uri specified in the last parameter is made.
简单翻译下:
- 语法:
try_files file ... uri;try_files file ... =code; - 可用上下文
content:可以在server,location下面使用
try_files 按指定顺序检查文件是否存在,并使用第一个找到的文件进行请求处理;处理在当前 上下文 中执行。其中 file 遵循该 context 中所提供的 root / alias 为根目录,往后寻找相对路径的结果。可以通过在名称末尾指定斜杠来检查目录是否存在,例如“$uri/”。如果没有找到任何文件,则会对上一个参数中指定的“uri”进行内部重定向。
用我们文章开始的 nginx 配置语法说明下: try_files $uri $uri/ /osp/index.html;
当用户请求 https://op-dev.xxxxxx.cn/osp 时,这里的 $uri 就是 /osp。
1、try_files 会尝试到alias或 root 指定的目录下找这个文件。如果存在名为 {alias指定目录}/osp 的文件,就直接把这个文件的内容发送给用户。
2、很显然,目录中没有叫 osp 的文件。然后就看 $uri/,增加了一个 /,也就是看有没有名为 {alias指定目录}/osp/ 的目录。(当我们访问URI时;如果访问资源为一个目录,并且URI没有以正斜杠(/)结尾;Nginx 服务就会返回一个301跳转,目标地址就是要加一个正斜杠)
3、如果又找不到,依次往后找,直到最后一个选项,如我们这里的 /osp/index.html,发起一个内部重定向,也就是相当于 nginx 发起一个 HTTP 请求到https://op-dev.xxxxxx.cn/osp/index.html。
我们通过写死 $uri/index.html 避免了重定向 ,因为我们这个项目是前端的SPA项目,目录下只会有index.html,故也不用考虑那么多。
tips: 我这边其实感觉还是没有解释清楚为什么
$uri/会触发重定向,而$url/index.html缺不会触发。实在是不知道该如何说服自己,我猜大概是因为$url/认为是一个目录需要触发重定向来请求下面默认的index指定的文件。这里留个疑问,待我摸索透彻了再补充。
为什么会从 https 重定向到 http 上
Nginx 重定向中的三个配置:absolute_redirect、server_name_in_redirect、port_in_redirect。
官方文档参考:http://nginx.org/en/docs/http/ngx_http_core_module.html#absolute_redirect
- absolute_redirect
语法: absolute_redirect on | off; 默认: on 绝对重定向 可用上下文: `http`, `server`,`location`
通过该指令控制 nginx 发出的重定向地址是相对还是绝对地址:
1、如果设置为 off,则 nginx 发出的重定向将是相对的,没有域名和端口, 也就没有server_name_in_redirect和port_in_redirect什么事儿了
2、如果设置为 on,则 nginx 发出的重定向将是绝对的;只有 absolute_redirect 设置为 on,server_name_in_redirect 和 port_in_redirect 的设置才有作用。
- server_name_in_redirect
语法: server_name_in_redirect on | off; 默认: off 关闭 可用上下文: `http`, `server`,`location`
server_name_in_redirect默认为off,使用请求URL中的域名部分作为Location中的域名(server_name)。若设置为on使用nginx配置中的server_name
- port_in_redirect(
我测试的 nginx v1.20 版本里已经没有这个配置了,可能是因为暴露端口非常危险吧。)
语法: absolute_redirect on | off;
默认: on 开启
可用上下文: `http`, `server`,`location`
port_in_redirect默认为on,使用 nginx 的监听端口作为Location中的端口部分。若设置为off则 Location 不设置端口
根据上面的配置说明,只需要修改 absolute_redirect 为 off ,使用相对路径重定向的方式就可以解决 https 跳转错误的问题。下面我们看下对比:
absolute_redirect为off,使用相对路径
absolute_redirect为on,使用绝对路径
ps: 这边为什么是
http的域名,而不是https,我继续猜一下... 这应该是ssl证书是在上层设置的,请求回到这台服务器的正式请求还是http的,所以内部重定向的时候也变成了http。(不知道说法是否正确,希望有运维大牛指教)