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。(不知道说法是否正确,希望有运维大牛指教)