Nginx Rewrite +正则表达式

116 篇文章 16 订阅
23 篇文章 7 订阅


前言

现在 Nginx 已经成为很多公司作为前端反向代理 (proxy pass) 服务器的首选,在实际工作中往往会遇到很多跳转(重写URL)的需求。比如,更换域名后需要保持旧的域名能跳转到新的域名上、某网页发生改变需要跳转到新的页面、网站防盗链等等需求。如果在后端使用的Apache服务器,虽然也能做跳转,规则库也很强大,但是用 Nginx 跳转效率会更高。


一、Nginx Rewrite概述

1. Rewrite 跳转场景

  • 调整用户浏览的 URL,看起来更规范,合乎开发及产品人员的需求。
  • 为了让搜索引擎搜录网站内容及用户体验更好,企业会将动态URL地址伪装成静态地址提供服务。
  • 网址换新域名后,让旧的访问跳转到新的域名上。例如,访问京东的 360buy.com 会跳转到 jd.com。
  • 服务端某些业务调整,比如根据特殊变量、目录、客户端的信息进行 URL 调整等

2. Rewrite 跳转实现

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

在这里插入图片描述

3. Rewrite 实际场景

① Nginx 跳转需求的实现方式

  • 使用 rewrite 进行匹配跳转

  • 使用 if 匹配全局变量后跳转

  • 使用 location 匹配再跳转

② rewrite 放在 server{},if{},location{} 段中

  • location 只对域名后边的除去传递参数外的字符串起作用——页面文件的路径

③ 对域名或参数字符串

  • 使用 if 全局变量匹配
  • 使用 proxy_pass 反向代理

二、Nginx 正则表达式

1. 常见的正则表达式元字符

字符说明
^匹配输入字符串的起始位置
$匹配输入字符串的结束位置
*匹配前面的字符零次或多次
+匹配前面的字符一次或多次
?匹配前面的字符零次或一次
.匹配除”\n”之外的任何单个字符
\将后面接着的字符标记为一个特殊字符或一个原义字符或一个向后引用
\d匹配纯数字
{n}重复n次
{n,}重复n次或更多次
[c]匹配单个字符c
[a-z]匹配a-z小写字母的任意一个
[a-zA-Z]匹配a-z小写字母或A-Z大写字母的任意一个

2. nginx 与 apache 区别

正则表达式是二者的区别之一
正则表达式:可以更加精确的匹配需求的字符串/参数/位置等

三、Rewrite 命令详解

1. 语法格式

rewrite <regex> <replacement> [flag];

#<regex>:正则表达式        
#<replacement>:跳转后的内容     
#[flag]rewrite支持的flag标记

2. flag 标记

标记说明
last相当于Apache的[L]标记,表示完成rewrite
break本条规则匹配完成即终止,不再匹配后面的任何规则
redirect返回302临时重定向,浏览器地址会显示跳转后的URL地址,爬虫不会更新url
permanent返回301永久重定向,浏览器地址会显示跳转后的URL地址,爬虫更新url
  • last 和 break 比较
lastbreak
使用场景一般写在 server 和 if 中一般使用在 location 中
URL匹配不终止重写后的 urI 匹配终止重写后的 url 匹配
  • last:url 重写后,马上发起一个新请求,再次进入 server 块,重试 location 匹配,超过10次匹配不到报 500 错误,地址栏不变;
  • break:url重写后,直接使用当前资源,不再使用location余下的语句,完成本次请求,地址栏不变

总的来说:last 和 break 再重定向后,地址栏都不会发生变化,这是他们的相同点。不同点在于 last 会写在 server 和 if中,break 是写在location 中,last 不会终止重写后的 url 匹配,break 会终止重写后的 url 匹配。

四、location 解析

1. location 分类

location = patt {}  [精准匹配]   			 #精确匹配字符串
location patt {}    [一般匹配]				 #只要包含patt的字符串即可
location ~ patt {}  [正则匹配]				 #按照正则表达式的方式匹配

2. 正则匹配的常用表达式

标记说明
~执行一个正则匹配,区分大小写
~*执行一个正则匹配,不区分大小写
!~执行一个正则匹配,区分大小写不匹配
!~*执行一个正则匹配,不区分大小写不匹配
^~普通字符匹配,使用前缀匹配,如果匹配成功,则不再匹配其他location
=普通字符精确匹配,也就是完全匹配
@定义一个命名的location,使用在内部定向时

3. location 优先级

  • 相同类型的表达式,字符串长的会优先匹配

  • 按优先级匹配

= 类型                                     			 #首先精确匹配
^~ 类型表达式								  			 #其次前缀匹配
正则表达式(~~*)类型					  			 #其次是按文件中顺序的正则匹配
常规字符串匹配类型,按前缀匹配				   			 #然后匹配不带任何修饰的前缀匹配	
通用匹配(/,如果没有其他匹配,任何请求都会匹配到 		 	 #最后交给 / 通用匹配

4. 优先级示例

-------------------------------------------------------------------------------------------------
location = / {                     
[configuration A]
}
#精确匹配,主机名后面不能带任何字符串,比如访问//data,则/匹配,/data不匹配;
比如location = /abc,则只匹配/abc,/abc//abcd不匹配;
若location /abc,则匹配/abc、/abcd/ 同时也匹配/abc/
-------------------------------------------------------------------------------------------------
location / {                     
[configuration B]
}
#一般匹配,所有的地址都以/开头,这条规则将匹配到所有请求,比如访问/和data,则/匹配,/data也匹配,但若后面是正则表达式和最长字符会优先匹配
------------------------------------------------------------------------------------------------
location /documents/ {            
[configuration C]
}
#匹配任何以/documents/开头的地址,匹配符合以后,还要继续往下搜索其他location,只有当后面的正则表达式没有匹配到时,才会采用这一条
------------------------------------------------------------------------------------------------
location ~ /documents/abc {     
[configuration D]
}
#匹配任何以/documents/abc开头的地址,匹配符合以后,还要继续往下搜索其他location,只有当后面的正则表达式没有匹配到时,才会采用这一条
------------------------------------------------------------------------------------------------
location ^~ /images/ {     
[configuration E]
}
#匹配任何以/images/开头的地址,匹配符合以后,停止往下匹配
------------------------------------------------------------------------------------------------
location ~* \.(gif|jpg|jpeg)$ {    
 [configuration F]
}
#匹配所有以gif,jpg或jpeg结尾的请求,因为 ^~ 的优先级最高
------------------------------------------------------------------------------------------------
location ~ /images/abc {           
 [configuration G]
 }
#匹配以/images/abc开头的,优先级次之,只有去掉location ^~ /images/才会采用这一条
------------------------------------------------------------------------------------------------
 location /images/abc/1.html {     
 [configuration H]
}
 #匹配/images/abc/1.html文件,如果和正则location ~ /images/abc/1.html相比,正则优先级最高
 ----------------------------------------------------------------------------------------------
 location /images/abc {             
[configuration I] 
 }
 #最长字符匹配到/images/abc,优先级最低,继续往下搜索其他location,会发现 ^~~ 存在
 ----------------------------------------------------------------------------------------------

5. rewrite 和 location 比较

  • 相同点:都能实现跳转
  • 不同点:
    ① rewrite 是在同一域名内更改获取资源的路径
    ② location是对一类路径控制访问或反向代理,还可以 proxy_pass 到其他机器
  • rewrite会写在location里,执行顺序
    ①执行server块里面的rewrite指令
    ②执行location匹配
    ③执行选定的location中的rewrite指令

6. location 优先级规则

① 那么 location 优先级到底是怎么排列的?

  • 匹配某个具体文件
(location = 完整路径)>(location ^~ 完整路径)>(location ~* 完整路径)>(location ~ 完整路径)>(location 完整路径)>(location /
  • 用目录做匹配访问某个文件
(location = 目录)>(location ^~ 目录/>(location ~ 目录)>(location ~* 目录)>(location 目录)(location /

② 文件和目录为什么只会在区不区分大小写上会有变动?

  • 正则表达式的目的是为了尽量精确的去匹配
  • 文件,尽量精确的匹配,不区分的话更容易找到
  • 目录,尽量精确匹配,区分大小写优先级更高,更容易找到

③ 在实际网站使用中,至少要有三个匹配规则定义

-------------------------------------------------------------------------------------------------
#第一个必选规则: 直接匹配网站根,通过域名访问网站首页比较频繁(www.baidu.com/),使用这个会加速处理,比如说官网;
可以是一个静态首页,也可以直接转发给后端应用服务器
location = / {
	root	html ;
	index index.html index.htm;
}
-------------------------------------------------------------------------------------------------
#第二个必选规则:处理静态文件请求,这是nginx作为http服务器的强项;
有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {
	root /webroot/static/ ;
}
location ~* \. (html|gif|jpg|jpeg|png)$ {
	root /webroot/res/ ;
} 
------------------------------------------------------------------------------------------------
#第三个必选规则就是通用规则,比如用来转发带.php、.jsp后缀的动态请求到后端应用服务器,
非静态文件请求就默认是动态请求,即跳转或反向代理
upstream	tomcat_ server {
	192.168.8.135:80
	192.168.8.132:80
location / {
	proxy_pass http://tomcat_server;
}
------------------------------------------------------------------------------------------------

五、案例解析

1. 基于域名的跳转

公司旧域名 www.gkd.com 因业务需求的变更,需要使用新域名 www.haha.com 代替,但是旧域名不能废除,并且旧域名要可跳转到新的域名上,而且后面的参数保持不变。

  • ① 添加映射,开启 nginx 服务
[root@localhost ~]#systemctl status nginx.service 
● nginx.service - nginx
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since 六 2021-10-09 00:30:45 CST; 3 days ago

[root@localhost ~]#vim /etc/hosts
......
192.168.8.135 www.gkd.com www.haha.com
  • ② 创建日志目录,修改主配置文件
[root@localhost ~]#mkdir -p /var/log/nginx
[root@localhost ~]#vim /usr/local/nginx/conf/nginx.conf
......
	server {
	    listen       80;
        server_name  www.gkd.com;                  		 #修改域名
        charset utf-8;									 #字符集可选择性修改
        access_log  /var/log/nginx/www.gkd.com.log; 	 #开启并对日志保存路径进行修改
	    location / {									 #在原有的location位置进行插入下面内容
			if ($host = 'www.gkd.com'){						 #$host为rewrite全局变量,表示请求主机头字段或主机名
			    rewrite ^/(.*)$ http://www.haha.com/$1 permanent;	#$1为匹配的位置变量,即域名后面的字符串,同时永久跳转
			}                    							 
		root   html;
		index  index.html index.htm;
	    }
......
	}
......

[root@localhost ~]#nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@localhost ~]#systemctl restart nginx.service 
  • ③ 使用浏览器进行验证
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 我们可以看到此时访问 www.gkd.com 时会自动跳转到 www.haha.com 上进行访问,并且在访问www.gkd.com/1.txt 时在错误页面显示时可以看到域名也发生了变化,变成了www.haha.com/1.txt。

2. 基于 IP 地址访问跳转

由于公司的业务新版本上线,要求所有 IP 访问任何内容都显示一个固定的维护页面,只有公司自己的IP地址 192.168.8.135 才能正常访问。

  • ① 创建维护页面的目录,并添加内容
[root@localhost /usr/local/nginx/html]#mkdir -p /var/www/html
[root@localhost /var/www/html]#vim weihu.html
网站维护中~~~~~~~~~~
  • ② 主配置文件配置
......
server {
listen       80;
server_name  www.gkd.com;
charset utf-8;
access_log  /var/log/nginx/www.gkd.com.log;      #开启并对日志保存路径进行修改
set $rewrite true;								 #设置变量$rewrite,变量值为布尔值为true
if ($remote_addr = "192.168.8.135"){	#当客户端ip为192.168.8.135时,将变量值设为flase,不进行重写
set $rewrite false;
}										#除了合法IP,其他都是非法IP,进行重写跳转到维护页面
if ($rewrite = true){                   #布尔值表达式在不满足false情况下,会匹配满足true的location
rewrite (.+) /weihu.html;				#重写在访问IP后边加入/weihu.html,如192.168.8.135/weihu.html
}
location = /weihu.html {
root /var/www/html;						#页面返回/var/www/html/weihu.html里面的内容
}
location / {
root   html;
index  index.html index.htm;
}
......
  • ③ 检测配置文件语法,重启服务
[root@localhost /usr/local/nginx/html]#nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@localhost /usr/local/nginx/html]#systemctl restart nginx.service 
  • ④ 打开浏览器进行验证

此时用另一台机器进行访问192.168.8.135这个地址,会发现页面进行了跳转,跳转到维护的页面,只有IP地址为192.168.8.135的本机才可正常访问

在这里插入图片描述
在这里插入图片描述

3. 基于旧域名跳转到新域名后面加目录

要求:当访问的域名为 http://bbs.gkd.com/post/1.html 时自动跳转到 http: //www.haha.com/bbs/post/1.html

  • ① 创建一个bbs目录下post的网页文件,并添加内容
[root@localhost /var/www/html]#mkdir -p /usr/local/nginx/html/bbs/post
[root@localhost /var/www/html]#vim /usr/local/nginx/html/bbs/post/1.html
[root@localhost /var/www/html]#cat /usr/local/nginx/html/bbs/post/1.html 
<h1>文档有毒~~~~~~</h1>
[root@localhost /var/www/html]#vim /etc/hosts
192.168.8.135 bbs.gkd.com www.haha.com
  • ② 主配置文件配置
.......
server {
listen       80;
server_name  bbs.gkd.com;								#更改域名					
charset utf-8;
access_log  /var/log/nginx/www.gkd.com-access.log;      #开启并对日志保存路径进行修改
location /post {										#添加location;以post开头匹配
rewrite (.+) http://www.haha.com/bbs$1 permanent;       #$1为位置变量,代表/post
}
location / {
root   html;
index  index.html index.htm;
}
......
  • ③ 检查主配置文件语法并重启服务
[root@localhost /var/www/html]#nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@localhost /var/www/html]#systemctl restart nginx.service 
  • 打开浏览器进行验证

在这里插入图片描述

在这里插入图片描述

可以看到此时域名已经自动跳转到了 http: //www.haha.com/bbs/post/1.html

4. 基于参数匹配(多余)的跳转

要求:访问 http://www.gkd.com/100-(100|200)-100.html 会跳转到 http://www.gkd.com的页面

  • ① 主配置文件配置
[root@localhost /var/www/html]#vim /usr/local/nginx/conf/nginx.conf
......
server {
listen       80;
server_name  www.gkd.com;							#更改域名
charset utf-8;
access_log  /var/log/nginx/www.gkd.com-access.log;  #开启并对日志保存路径进行修改
#设置正则匹配,例如:http://www.gkd.com/100-100-123.html													
if ($request_uri ~ ^/100-(100|200)-(\d+)\.html$){   #$repuest_uri内置变量,表示uri,\d 纯数字
rewrite (.*) http://www.gkd.com permanent;			#设置重写
}
location / {
root   html;
index  index.html index.htm;
}
......
  • ② 检查主配置文件语法并重启服务,配置映射
[root@localhost /var/www/html]#nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@localhost /var/www/html]#systemctl restart nginx.service 
[root@localhost /var/www/html]#vim /etc/hosts
192.168.8.135 www.gkd.com
  • ③ 使用浏览器进行验证
    在这里插入图片描述
    在这里插入图片描述

可以看到访问域名 http://www.gkd.com/100-100-100.html 时直接跳转到了 http://www.gkd.com 的页面
访问 http://www.gkd.com/100-200-100.html 也可跳转

5. 基于目录下所有 php 结尾的文件跳转

要求:访问 http://www.gkd.com/upload/123.php 跳转到首页(常用场景:网站新用户提示需要注册)

  • ① 主配置文件配置
[root@localhost /var/www/html]#vim /usr/local/nginx/conf/nginx.conf
......
server {
listen       80;
server_name  www.gkd.com;
charset utf-8;
access_log  /var/log/nginx/www.gkd.com-access.log;
location ~* /upload/.*\.php$ {         
# ~* 表示正则匹配,不区分大小写,匹配/upload目录下所有以.php结尾的文件
rewrite (.*) http://www.gkd.com permanent;
}
location / {
root   html;
index  index.html index.htm;
}
......


  • ② 检查主配置文件语法并重启服务
[root@localhost /var/www/html]#nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@localhost /var/www/html]#systemctl restart nginx.service 
  • ③ 打开浏览器进行验证

在这里插入图片描述

在这里插入图片描述

可以看到访问 http://www.gkd.com/upload/123.php 会跳转到 http://www.gkd.com 首页

6. 基于最普通一条 url 请求的跳转

要求:访问一个具体的页面,如: http://www.gkd.com/abc/123.html,能跳转到首页

  • ① 主配置文件配置
[root@localhost /var/www/html]#vim /usr/local/nginx/conf/nginx.conf
......
    server {
        listen       80;
        server_name  www.gkd.com;
        charset utf-8;
        access_log  /var/log/nginx/www.gkd.com-access.log;
        location ~* /abc/123.html {                     
                rewrite (.+) http://www.gkd.com permanent;
        }
        location / {
            root   html;
            index  index.html index.htm;
        }

......
  • ② 检查主配置文件语法并重启服务
[root@localhost /var/www/html]#nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@localhost /var/www/html]#systemctl restart nginx.service 
  • ③ 使用浏览器进行验证

在这里插入图片描述
在这里插入图片描述

可以看到访问 http://www.gkd.com/abc/123.html 的时候进行了跳转,跳转到了主页面!

总结

  • 配置跳转的原因:为了让URL看起来更规范、合理;企业会将动态URL地址伪装成静态地址提供服务;网址换新域名后,期望用户可以通过旧的访问跳转到新的域名上;服务端某些业务调整

  • Nginx跳转需求的实现方式:①使用rewrite进行匹配跳转(主要匹配的是具体的路径);②使用if匹配全局变量后跳转,结合布尔值时间true和fales的跳转③使用location匹配再跳转(可以匹配后执行proxy_pass,将请求跳转到其他服务上)

  • nginx 服务基于 http 协议 rewrite 重写 mudule 模块,主从URL重写,其中有一个布尔值:返回值的结果只有true或者false;只支持if单分支语句

  • location 分类:① location = patt{} [精准匹配];② location patt {} [一般匹配];③ location ~ patt {} [正则匹配]

  • location 的匹配优先级为:首先精确匹配,其次是前缀匹配,再其次是按文件中顺序的正则匹配,然后匹配不带任何修饰的前缀匹配 ,最后交给 / 进行通用匹配。

参考:
Nginx中的Location和Rewrite

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值