Nginx 301重定向分析

news2024/12/23 9:48:27

参考;

404 - 墨天轮

深度硬核文:Nginx的301重定向处理过程分析 - 知乎

Nginx的301状态码处理逻辑设计

HTTP协议中3xx开头的状态响应码都是表示重定向的响应。根据RFC的定义:

301 Moved Permanently

302 Found

303 See Other

307 Temporary Redirect

301是永久重定向。如果使用Nginx作为HTTP 服务器,那么当用户输入一个不存在的地址之后,基本上会有两种情况,返回404状态码,或者301状态码。404 Not Found不做讨论,只是说下301 Moved Permanently的处理过程。

页面重定向功能会在什么样的情况下被触发?

答案是:Nginx负责设置301 Moved Permanently状态码。但nginx.conf控制Nginx如何处理301 Moved Permanently状态码!换句话说,要不要进行页面重定向,和怎么重定向,完全是用户配置的结果!六种分支的选择完全是根据用户的配置来决定的。

根据源代码,Nginx的算法逻辑设计是分成两个部分的。第一部分是设置状态码,第二部分是对应状态码的实际响应处理。

Nginx和浏览器之间的通讯过程,比如一次正常的HTTP 访问过程,如下图。

从逻辑顺序上来说,Nginx会先设置好状态码,然后根据状态码来构造Response Header和Body,最后发送给浏览器,让浏览器渲染页面内容。

301 Moved Permanently状态码和200 OK状态码的处理过程是一致的。Nginx主动设置301 Moved Permanently状态码只有一种情况,当用户输入了一个url地址,最后的部分是一个文件目录。比如 http://www.test.com/index, Nginx在运行过程中没有找到index这个文件,但发现了index是个目录。于是本次访问的状态码就会被设置成301 Moved Permanently。

但注意!设置成301 Moved Permanently,不一定会导致浏览器重定向。从HTTP定义来说,导致浏览器触发重定向操作是因为浏览器收到了一个Locationresponse header;

让我们来看看Location的定义说明,很明确的说明了Location的作用。

The Location response header indicates the URL to redirect a page to. It only provides a meaning when served with a3xx (redirection) or 201(created) status response.

Nginx在Response Header里写入一个Location之后。浏览器可以根据Location来控制重定向过程。逻辑过程如上图。而且nginx.conf文件中的配置将影响到Location URL的生成方式。

nginx.conf中配置项的作用

nginx.conf文件在哪个环节起作用呢?答案就是设置Location之前。

 

一般情况下,我们会在nginx.conf中配置absolute_redirect ,server_name_in_redirect和port_in_redirect,以便到达个性化的重定向功能。这三个配置项的作用是很多人明白的,但对于逻辑顺序很少有文章提到。

重定向三配置

absolute_redirect ,server_name_in_redirect和port_in_redirect三个设置项中,根据Nginx的源代码中Response Header处理算法逻辑,Nginx能够控制重定向的关键配置项是:absolute_redirect,在整个Nginx代码中,absolute_redirect在控制在Response Header如何增加Location url。

absolute_redirect设置成On,则生成absolute url作为Location url。absolute_redirect设置成Off,则生成relative url作为 Location url。

absolute url是包含完整信息的url,比如http://www.test.com:8080/index/1.html 这样的URL地址relative url 则省略了服务器名字和端口号,比如 /index/1.html

因为relative url没有端口号,没有Host名字,所以absolute_redirect 设置On的时候,server_name_in_redirect和port_in_redirect两项设置才会起作用。

我花了点时间仔细阅读了Nginx的相关源代码,并画了流程图。

 

从以上逻辑过程, absolute_redirect,server_name_in_redirect,port_in_redirect 三项配置,共同控制了生成字符串 “Location: http://server_name:port/test/”的结果。

server_name_in_redirect 控制URL中的Server Name,也就是Host使用哪个值,port_in_redirect控制URL中的port是使用哪个值。通过这三个配置项,最终决定了Nginx返回给浏览器的Location内容。

用MindMap来表达就是

 

备注:header_in.server是nginx源代码中的变量,指向用户输入的url的服务器名字部分。根据以上脑图,我们可以很清楚的看到,最终我们只有六个分支结果。

案例分析

依据上面的分析,我们具体举个非常疑难的例子,看看如何解决问题。

1,问题:http://www.test.com:888/index被错误的重定向至http://www.test.com/index/这种情况多见于使用NAT做端口映射,或者是用容器来运行Nginx。内部服务器或者容器中nginx监听的是80端口号

而我们的期望答案是:http://www.test.com:888/index重定向至http://www.test.com:888/index/

2,分析和解答:假设Nginx使用默认设置

absolute_redirect:on

server_name_in_redirect:off

port_in_redirect :on

这个问题看似丢失了端口号,实际上是暴露了nginx的内部端口号。这种情况下,port_in_redirect不管设置成on或者off都不会起作用。

port_in_redirect = on,nginx监听80端口,默认80端口号不需要在url中设置【3号分支】,结果是http://www.test.com/index/

port_in_redirect = off,nginx不设置port数据【5号分支】,结果还是http://www.test.com/index/

我们会发现,在这里无论怎么调整server_name_in_redirect【1,2号分支】和port_in_redirect的on,off都是无效的。因为1号至5号分支,都没有包含这种情况。解决问题的方向错了,解决方案当然就是错误的。

实际的解决方案有两个: rewrite【分支以外】 absolute_redirect:off【六号分支】 rewrite是通过脚本来控制nginx的运行过程,不在上面的配置分支中。具体操作可以参考下面的设置

rewrite [^/]$ $scheme://$http_host$uri/ permanent;备注:rewrite的操作方式依据不同的目录结构,可能略有不同,请根据实际情况来设置。

absolute_redirect:off,就是六号分支absolute_redirect:off之后,Nginx返回Location:/index/,但这个方式也许会带来其他问题。

absolute_redirect

1. 设置absolute_redirect

1) absolute_redirect为off。

server { server_name sample_test.xyz sample_preview.xyz; server_name_in_redirect off; listen 9098;  port_in_redirect on;  absolute_redirect off;  root html/; }

当前absolute_redirect指令设置的是off,此时头部的Location部分是不会出现协议、主机名还有端口。


2)absolute_redirect为on。

server { server_name sample_test.xyz sample_preview.xyz;  server_name_in_redirect off;  listen 9098;  port_in_redirect on;  absolute_redirect on;  root html/; }

当absolute_redirect指令设置为on,头部的Location部分则出现协议、主机名还有还有端口。

2. 设置server_name_in_redirect

1) server_name_in_redirect 为off。

server { server_name sample_test.xyz sample_preview.xyz;  server_name_in_redirect off;  listen 9098;  port_in_redirect on;  absolute_redirect on;  root html/; }

将server_name_in_redirect指令设置为off,会使用请求头中Host的值。这里杨杨在请求时添加头部信息,可以看到Location中的域名变成了aaa。



2)server_name_in_redirect 为on。

server { server_name sample_test.xyz sample_preview.xyz; server_name_in_redirect on; listen 9098; port_in_redirect  on;absolute_redirect on; root html/;}

将server_name_in_redirect指令设置为on,会location会使用配置文件中的server_name


3. 设置port_in_redirect
1) port_in_redirect为off。

server { server_name sample_test.xyz sample_preview.xyz;  server_name_in_redirect off;  listen 9098;  port_in_redirect off;  absolute_redirect on;  root html/; }

当port_in_redirect指令的值设置为off,location中就不会展示出访问的端口号。



在前几个例子中,port_in_redirect指令的值为on,此时location中会展示出端口号。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/783547.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STL——String类(2)成员函数详解

目录 前言 一.String的成员函数: 1.基本成员函数 代码实验: 实验结果: 类对象每次扩容后的capacity数据展示: 1.2. resize():调整字符串大小 1.3reserve():请求更改该对象的容量capacity值 代码实验…

分组密码模式的填充

分组加密 在密码学中,分组加密(Block cipher),又称分块加密或块密码,是一种对称密钥算法。 它将明文分成多个等长的模块(block),使用确定的算法和对称密钥对每组分别加密解密。 常见的分组加密算法有: DES、3DES、AES、IDEA。 …

Ubuntu虚拟机部署配置

目录 虚拟机镜像下载 VirtualBox7下载 VirtualBox7安装镜像流程 创建虚拟机 虚拟机挂单独硬盘 网络设置 检查虚拟机配置 启动虚拟机 ubuntu配置 查询虚拟机IP地址 修改ROOT密码 更新apt NTP同步 挂载磁盘&关闭swap 虚拟机镜像下载 目前国内操作系统镜像源非常…

2023-07-19力扣今日二题

链接: 2737. 找到最近的标记节点 题意: 给一个n节点有向图,求节点s和点集marked中的最短距离,没有可以的到达的点则返回-1 解: 摇了一题困难过了2/3,搞不定了 没有负权边的单源最短距离,迪…

代码-【2 单链表A、B交集存放到C】

1)基本思想: A、B两个链表的元素均递增有序,所以可以按顺序,同时从A中和B中各取一个结点的值来对比;如果A中结点的值比较小,则A中的指针右移;如果B中的结点的值比较小,则B中的指针右…

优思学院|工程师学习六西格玛有什么用?

很久以前,世上没有当今盛行的各种简单易用的统计软件,那时复杂的统计分析只能依靠公司的统计顾问。而和他们在一起工作时,工程师必须知道怎样进行提问。 如果工程师缺乏对统计工具的认识,即使拿到正确的工具也于事无补。当顾问遇…

2. Makefile之目标、依赖(附示例)

一、本节概要 本专栏所有内容围绕Makefile官方文档进行刨析,给出详细具体示例做辅助理解手撕Makefile官方手册 二、Makefile中的目标和依赖 在一个简单的Makefile中,每条规则通常由以下几个部分组成: target ... : prerequisites ...rec…

修改虚拟机ip为静态ip

在使用虚拟机的时候,默认情况下使用的DHCP协议分配的动态IP地址,使得每次打开虚拟机后当前的IP地址都可能会发生变化,这样不方便管理。为了能够给当前虚拟机设置一个静态IP地址,方便后期使用XShell等连接工具进行连接,…

C/C++内存分布

C/C内存管理 1.C/C内存分布2.C语言中动态内存管理方法2.1 malloc/calloc/realloc/free 3.C内容管理方法3.1new/delete操作内置类型3.2 new和delete操作自定义类型 4.operator new与operator delete函数5.new和delete的实现原理5.1内置类型5.2自定义类型 6定位new表达式&#xf…

Libtorch 在x86_64的Linux 上部署时的版本问题

1. ubuntu 上安装了cuda12.1 和cuda 12.2 ,但是NVCC 指向的是10.1,但是10.1 又没有安装, 所以版本很混乱 ./usr/bin/nvcc -> 10.1./usr/lib/nvidia-cuda-toolkit/bin/nvcc-> 10.1./usr/local/cuda-12.1/bin/nvcc -> 12.1./usr/local/cuda-12.2…

RT-Thread快速入门-线程管理

在 RT-Thread 中,最基本的调度单位是线程,其他 RTOS 也叫任务。如果学习过或者了解过 RTOS,任务这种叫法是最为熟知的。 本篇文章来学习一下 RT-Thread 线程方面的内容。对于初学者来说,转换一下思维,建立多任务&…

Docker部署Redis集群详解【主从复制 + 哨兵模式】

前言 注意:该文章不会讲解Redis集群搭建的原理,只讲述如何通过Docker容器快速部署搭建Redis主从 哨兵模式的集群 准备工作: 一台云服务器 or 本地虚拟机(CentOS和Ubuntu都可以)安装好Docker环境(Docker、…

ROS框架——发布者功能包和订阅者功能包进行bool类型数据结构的topic通讯

ROS框架——发布者功能包和订阅者功能包进行bool类型数据结构的topic通讯 code review! 文章目录 ROS框架——发布者功能包和订阅者功能包进行bool类型数据结构的topic通讯零.同时运行两个功能包一.发布者功能包1.1.文件结构1.2.bool\_publisher\_node.cpp1.3.CMakeLists.txt…

SpringBoot实战(二十一)集成 TLog 日志

目录 一、简介二、Maven依赖三、启动类集成四、测试1.服务简介2.服务A代码DemoController.javaDemoFeignClient.java 3.服务B代码4.测试结果 补充一:自定义日志标签模板补充二:SpanId的生成规则补充三:业务标签1.打印入参2.指定连接符3.打印常…

【深度学习-卷积神经网络CNN-基础】

文章目录 发展历史卷积神经网络的应用领域卷积的原理和作用卷积和传统的神经网络的区别 卷积网络的整体架构输入层卷积层池化层全连接层卷积和池化叠加多层卷积可以处理什么类型的数据卷积的超参数卷积最大的优势 卷积的细节卷积的原理卷积的参数卷积的次数步长 卷积核尺寸 边缘…

成为UI设计高手:如何规划和创建UI设计组件库!

今天给大家分享一篇关于组件化设计的总结,希望可以带给大家更多设计思考。 什么是组件化 组件化化是构成界面的最基础元素和重复出现控件的集合体,也就是常说的组件库。通过对基础元素和控件的规范命名与排列组合,最终形成一个可快速调用与便…

每日一题——地下迷宫(迷宫问题II)

迷宫问题(地下迷宫)——II 题目链接 前言: 这题是在昨天迷宫问题——I的基础上进行的变形,因此,如果昨天的题目没看或者对迷宫问题不怎么了解,建议先看看昨天的解析。 迷宫问题——I源代码: …

安装redis,适配阿里云服务器,Liunx安装redis

下载redis以及编译安装 下载redis文件 wget http://download.redis.io/releases/redis-6.0.8.tar.gz #下载redis压缩文件 tar xzf redis-6.0.8.tar.gz #解压缩 cd redis-6.0.8 make 查看是否安装了gcc编译输入gcc --version如果没有…

AtcoderABC236场

A - chukodaiA - chukodai 题目大意 题目要求交换字符串S中第a个字符和第b个字符的位置,并输出结果。 思路分析 借用临时变量t,进行记录交换。 时间复杂度 O(∣S∣) 输出交换后的字符串的时间复杂度为O(∣S∣),其中∣S∣表示字符串SS的…

autohotkey实战:窗口透明化

文章目录 实现方法代码讲解WinGet和WinSet 注 本文采用的是V1版本语法 实现方法 窗口透明不仅实用性强,关键是非常炫酷,如果用AHK实现一个实时调节窗口透明度的工具,那么就可以一边敲代码,一边透过半透明的IDE,愉快地…