Nginx二级子路径请求,如何去掉尾部多余的"/"以及避免301重定向请求

发表于:2022-05-18 20:09:39·阅读:160

本文主要是讨论访问页面url触发了多余的重定向,以及末尾多了 / 问题。本文讨论的问题主要是使用 try_files 引起的问题,虽最终解决的方案并未去做 absolute_redirect 相关的配置修改,但实则也是与 absolute_redirect 相关。在本文也会主要对 try_filesabsolute_redirect 相关的参数配置进行说明。

问题背景

昨天在React项目中,通过代理的方式,从本地代理指向到开发环境域名下的一个二级目录部署的项目,发现通过本地地址访问一直无法正常。查看网络请求,发现代理的 URL 链接触发了 301 重定向,导致跳到了原来的域名下。

先看下出问题现象(其实也不算是问题,这是nginx的正常机制,请往下看):

image.png

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: serverlocation

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 :可以在 serverlocation 下面使用

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 会尝试到aliasroot 指定的目录下找这个文件。如果存在名为 {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_redirectserver_name_in_redirectport_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_redirectport_in_redirect什么事儿了
2、如果设置为 on,则 nginx 发出的重定向将是绝对的;只有 absolute_redirect 设置为 onserver_name_in_redirectport_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中的端口部分。若设置为offLocation 不设置端口


根据上面的配置说明,只需要修改 absolute_redirectoff ,使用相对路径重定向的方式就可以解决 https 跳转错误的问题。下面我们看下对比:

  • absolute_redirectoff,使用相对路径
    image.png

  • absolute_redirecton,使用绝对路径
    image.png

ps: 这边为什么是 http 的域名,而不是 https,我继续猜一下... 这应该是ssl证书是在上层设置的,请求回到这台服务器的正式请求还是http的,所以内部重定向的时候也变成了http。(不知道说法是否正确,希望有运维大牛指教)

参考资料:

评论
文明评论,理性发言
⌘ + Enter
全部评论
暂无评论数据