Nginx Rewrite

一、Nginx Rewrite概述

在实际工作中往往会遇到很多跳转(重写URL)的需求。比如:更换域名后需要保持旧的域名能够跳转到新的域名上、某网页发生改变需要跳转到新的页面、网站防盗链等等需求,使用Nginx跳转效率会更高

1.1、Rewrite跳转场景

Rewrite跳转场景主要包括以下几种:

》可以调整用户浏览的URL,看起来更规范,更符合开发及人员的需求

》为了让搜索引擎搜录网站内容及用户体验更好,企业将动态URL地址伪装成静态地址提供服务。

》网址换新域名后,让旧的访问跳转到新的域名上。例如,访问京东的360buy.com会跳转到jd.com

》根据特殊变量、目录、客户端的信息进行URL调整等

1.2、Rewrite跳转实现

Nginx是通过ngx_http_rewrite_module模块支持url重写、支持if条件判断。但是不支持else。另外该模块需要PCRE软件包的支持,默认已经安装。根据相关变量重定向和选择不同的配置,从一个location跳转到另一个location,不过这样的循环最多可以执行10次,超过后Nginx将返回500错误。同时,重写模块包含set执行,来创建新的变量并设其值,如记录条件标识、传递参数到其他location、记录做了什么等等。rewrite功能就是使用Nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现rul重写以及重定向

1.3、Rewrite实际引用场景

在实际工作的应用中,Nginx跳转需求三种方式可以实现。可以直接用rewrite进行匹配跳转,也可以使用if匹配全局变量后跳转。另外,还可以使用location匹配再跳转。所以rewrite只能放在server {}、if {} 、location{}配置段中。例如location只能对域名后面的除去传递的参数外的字符串起作用,例如http://www.kgc.com/index.php?id=1只能对/index.php重写。如果相对域名或者参数字符串起作用,可以使用if全局变量匹配,也可以使用proxy_pass反向代理

1.4、Nginx正则表达式

字符描述
^匹配输入字符串的起始位置(以什么开头)
$匹配输入字符串的结束位置(以什么结尾)
*匹配前面的字符零次或多次
+匹配前面的字符一次或多次
?匹配前面的字符零次或一次
.匹配除\n之外的任意单个字符
\将后面接着的字符标记为一个特殊字符或一个普通字符
\d匹配纯数字
{n}重复n次
{n,}重复n次或更多次
[c]匹配单个字符c
[a-z]匹配a-z小写字母的任意一个
[a-zA-Z]匹配a-z小写字母A-Z大写字母的任意一个

二、Nginx Rewrite基本操作

2.1、Rewrite语法

Rewrite命令的语法如下所示,其中regex表示正则匹配规则、replacement表示跳转后的内容、flag表示rewrite支持的flag标记

rewrite [flag];

flag标记说明:

》last:相当于Apache的[L]标记,表示完成rewrite。

》break:本条规则匹配完成即终止,不再匹配后面的任何规则。

》redirect:返回302临时重定向,浏览器地址会显示跳转后的URL地址,爬虫不会更新rul(因为是临时)

》premanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址,爬虫更新rul

如果后面不跟flag标记,那么默认是302临时重定向。在实际工作场景中,还有另一种return指定。因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return指定无法返回301和302的原因

last和break区别是:last一般卸载server和if中,而break一般使用location中。last不终止重写后的rul匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配

2.2、Location分类

location用来设置请求的Uri信息,可以根据用户请求的URI来执行不同的应用。

location大致可以分为三类,语法如下:

location = patt {} [精准匹配]

location patt {} [一般匹配]

location ~ patt {} [正则匹配]

精确匹配和一般匹配不需要做详细的说明,主要是正则匹配。下面就是正则匹配的一些表达式,需要多加牢记

》~:表示执行一个正则匹配,分区大小写

》~*:表示执行一个正则匹配,不区分大小写

》!~:表示执行一个正则匹配,区分大小写不匹配

》!~*:表示执行一个正则匹配,不区分大小写不匹配

》^~:表示普通字符匹配,使用前缀匹配。如果匹配成功,则不再匹配其他location

》=:进行普通字符精确匹配,也即是完全匹配

》@:它定义一个命名为location,使用在内部定向时,例如error_page,try_files

2.3、Location优先级

在Nginx的location匹配中location的顺序没有太大的关系。匹配优先级和location表达式的类型有关:相同类型的表达式,字符串长的会优先匹配

以下是按优先级排序说明:

》等号类型(=)的优先级最高。一旦匹配成功,则不再查找其他匹配项。

》^~类型表达式。一旦匹配成功,则不再查找其他匹配项。

》正则表达式类型(*)的优先级最低次之

》常规字符串匹配类型。按前缀匹配。用匹配(/),如果没有其他匹配,任何请求都会被匹配到

从功能看rewrite和location似乎有点像,都能实现跳转,主要区别在于rewrite是在同一域名内更改获取资源路径,而location是对一类路径做控制访问或反向代理,还可以proxy_pass到其他机器。很多情况下rewrite也会写在location里,他们的执行顺序如下

(1)执行server块里面的rewrite执行

(2)执行location匹配

(3)执行选定的location中的rewrite执行

下面根据不同的Location优先级进行示例说明。

#精确匹配/,主机名后面不带任何字符串
location = / {		##精确匹配
[configuration A]
}

#因为所有的地址都是以/开头,所以这条规则将匹配到所有请求,但是正则和最长字符串会优先匹配
location / { 	##最低级匹配
[configuration B]
}

#匹配任何以 /documents/开头的地址,匹配符合以后,还要继续向下搜索,只有后面的正则表达式没有匹配到时,这条才起作用
location /documents/ {
[configuration C]
}

#匹配任何以 /documents/abc开头的地址,匹配符合以后,还要继续向下搜索,只有后面的正则表达式没有匹配到时,这一条才会起作用
location ~ /documents/abc {
[configuration D]
}

#匹配任何以/images/开头的地址,匹配符合以后,停止向下匹配
location ^~ /images/ {
[configuration E]
}

#匹配所有以gif,jpg或jepg结尾的请求,然后所有请求/images/下的图片会被[configuration E]处理,因为^~的优先级更高
location ~* \.(jif|jpg|jepg)$ {		##正则匹配
[configuration F]
}

#最长字符匹配到/images/abc,优先级最低
location /images/abc {
[configuration G]
}

#匹配/images/abc开头的,优先级次之
location ~ /images/abc {
[configuration H]
}

#匹配/images/abc/1.html文件,如果和正则~ /images/abc.html相比,正则优先级更高
location /images/abc/1.html {
[configuration I]
}

现在,对location优先级进行总结

》如果是匹配某个具体文件:

精确匹配>>字符开头>>正则匹配>>通配

(location = 完整路径)>(location ^~ 完整路径)>(location ~* 完整路径) 正则匹配 >(location ~ 完整路径)>(location 完整路径)>(location /)

》如果是用目录做匹配访问某个文件:

(location = 目录)>(location ^~ 目录/)>(location ~ 目录)>(location ~* 目录)>(location 目录)>(location /)

三、Rewrite常见示例

资源列表

操作系统配置主机名IP
CentOS 72G2核rewrite192.168.93.101
CentOS 7图形化2G2核client192.168.93.11

基础环境

  • 关闭防火墙
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# systemctl disable firewalld
  • 关闭内核安全机制
[root@localhost ~]# setenforce 0
[root@localhost ~]# sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/selinux/config 
  • 修改主机名
[root@localhost ~]# hostnamectl set-hostname rewrite

3.1、yum安装Nginx服务

#查询是否安装rewirte所支持的软件包
[root@rewrite ~]# yum list | grep pcre	
#添加一个非常强大的EPEL存储库,不然不能安装nginx
[root@rewrite ~]# yum -y install epel-release
[root@rewrite ~]# yum -y install nginx

3.2、修改Nginx默认站点配置文件

#在路径下创建站点配置文件/etc/nginx/conf.d/
[root@rewrite ~]# cd /etc/nginx/conf.d/
[root@rewrite conf.d]# vim default.conf
server {
	listen 80;
	server_name www.kgc.com;
	charset utf-8;
	access_log /var/log/nginx/www.kgc.com-access.log main;
location / {
 	root /usr/share/nginx/html;
	index index.html index.htm;
}
}
[root@rewrite conf.d]# echo "<h1>www.kgc.com</h1>" > /usr/share/nginx/html/index.html 
[root@rewrite conf.d]# systemctl start nginx

#客户端查看是否可以访问到页面
[root@localhost ~]# echo "192.168.93.101 www.kgc.com" >> /etc/hosts
[root@localhost ~]# cat /etc/hosts | grep www.kgc.com
192.168.93.101 www.kgc.com
[root@localhost ~]# curl www.kgc.com
<h1>www.kgc.com</h1>

3.3、Rewrite示例

需要注意的是,在做每一步场景测试之前请确定www.kgc.com域名可以正常解析,每做下一个场景之前请删除上一个场景的配置。另外,要清除浏览器缓存。

3.3.1、基于域名的跳转

假如,现在公司旧域名www.kgc.com有业务需求变更,需要使用新的域名www.newkgc.com代替,但是旧域名不能废除,需要跳转到新的域名上,而且后面的参数保持不变。在/etc/nginx/conf.d/default.conf文件的location /下添加如下内容

location / {
if ($host = 'www.kgc.com')
{
rewrite ^/(.*)$ http://www.newkgc.com/$1 permanent;
}
 	root /usr/share/nginx/html;
	index index.html index.htm;
}
[root@rewrite ~]# systemctl reload nginx

#客户端需要在hosts文件中写入www.newkgc.com域名解析
[root@localhost ~]# echo "192.168.93.101 www.newkgc.com" >> /etc/hosts

可以看到访问旧域名www.kgc.com跳转到了新域名www.newkgc.com上,状态码是301永久重定向
在这里插入图片描述

域名后面加参数跳转,因为代码中很多请求是带参数的,所以要保证参数都能够正常跳转。浏览器输入模拟访问http://www.kgc.com/test/1/index.php(虽然这个页面请求是不存在的)跳转到http://www.newkgc.com/test/1/index.php,可以看到301实现了永久重定向,而且域名后的参数也正常跳转
在这里插入图片描述

e-20240406092837862.png&pos_id=img-yzOKJgN7-1716540373923)

3.3.2、基于客户端IP访问的跳转

例如今天公司业务版本上线,要求所有IP访问任何内容都显示一个固定的维护页面,只有公司IP访问正常。在/etc/nginx/conf.d/default.conf文件里添加如下内容。

[root@rewrite ~]# vim /etc/nginx/conf.d/default.conf 
set $rewrite true;
if ($remote_addr = "192.168.93.11") {
set $rewrite false;
}
if ($rewrite = true ){
rewrite (.+) /maintenance.html;
}
location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
}
[root@rewrite ~]# echo "Website is Maintaining,Please visit later." > /usr/share/nginx/html/maintenance.html
[root@rewrite ~]# systemctl reload nginx

只有IP地址为192.168.93.11能正常访问,其他地址都是维护页面,使用一个局域网的其它IP地址用浏览器访问http://www.kgc.com域名和加参数都是请求的maintenance.html页面的内容,而且状态码是200
在这里插入图片描述

3.3.3、基于旧域名跳转到新域名后面加目录

例如现在访问的是http://bbs.kgc.com,现在需要将这个域名下面的发贴都跳转到http://www.kgc.com/bbs,注意保持域名跳转后的参数不变。

[root@rewrite ~]# vim /etc/nginx/conf.d/default.conf 
server {
        listen 80;
        server_name bbs.kgc.com;	#更改域名
        charset utf-8;
location /post {
rewrite (.+) http://www.kgc.com/bbs$1 permanent;
        root /usr/share/nginx/html;
        index index.html index.htm;
}
}
[root@rewrite ~]# systemctl reload nginx


#客户端做域名解析
[root@localhost ~]# echo "192.168.93.101 bbs.kgc.com" >> /etc/hosts

模拟使用浏览器访问http://bbs.kgc.com/post/1.php 跳转到http://www.kgc.com/bbs/post/1.php
在这里插入图片描述

3.3.4、基于参数匹配的跳转

例如现在访问http://www.kgc.com/100-(100|200)-100.html跳转到http://www.kgc.com页面

[root@rewrite ~]# vim /etc/nginx/conf.d/default.conf 
server {
        listen 80;
        server_name bbs.kgc.com;
        charset utf-8;
if ($request_uri ~ ^/100-(100|200)-(\d+).html){
rewrite (.*) http://www.kgc.com permanent;
}
location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
}
}
[root@rewrite ~]# systemctl reload nginx

使用浏览器访问http://www.kgc.com/100-100-100.html
在这里插入图片描述

3.3.5、基于目录下所有php结尾的文件跳转

要求访问http://www.kgc.com/upload/1.php跳转到首页。

[root@rewrite ~]# vim /etc/nginx/conf.d/default.conf 
server {
        listen 80;
        server_name bbs.kgc.com;
        charset utf-8;
location ~* /upload/.*\.php$ {
rewrite (.+) http://www.kgc.com permanent;
        root /usr/share/nginx/html;
        index index.html index.htm;
}
}
[root@rewrite ~]# systemctl reload nginx

浏览器访问http://www.kgc.com/upload/1.php
在这里插入图片描述

3.3.6、基于最普通的一条url请求的跳转

要求访问一个具体的页面跳转到首页

[root@rewrite ~]# vim /etc/nginx/conf.d/default.conf 
server {
        listen 80;
        server_name bbs.kgc.com;
        charset utf-8;
location ~* ^/1/test.html{
rewrite (.+) http://www.kgc.com permanent;
        root /usr/share/nginx/html;
        index index.html index.htm;
}
}
[root@rewrite ~]# systemctl reload nginx

浏览器访问http://www.kgc.com/1/test.html跳转到首页
在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐