现在 Nginx 已经成为很多公司作为前端反向代理服务器的首选,在实际工作中往往会遇到很多跳转(重写 URL)的需求。比如:更换域名后需要保持旧的域名能跳转到新的域名上、某网页发生改变需要跳转到新的页面、网站防盗链等等需求,此时nginx rewrite 便起到了重要的作用
Rewrite 跳转场景主要包括以下几种:
可以调整用户浏览的 URL,看起来更规范,合乎开发及产品人员的需求。
网址换新域名后,让旧的访问跳转到新的域名上。例如,访问京东的 360buy.com 会跳转到 id.com。
Nginx 是通过 ngx_http_rewrite_module 模块支持 url 重写、支持if条件判断,但不支持 else。另外该模块需要 PCRE 支持,应在编译 Nginx 时指定 PCRE 支持,默认已经安装。根据相关变量重定向和选择不同的配置,从一个location 跳转到另一个location,不过这样的循环最多可以执行 10 次,超过后 Nginx 将返回 500 错误。同时,重写模块包含 set 指令,来创建新的变量并设其值,这在有些情景下非常有用的,如记录条件标识、传递参数到其他location、记录做了什么等等。rewrite 功能就是使用 Nginx 提供的全局变量或自己设置的变量,结合正则表达式和标志位实现 un 重写以及重定向。
在实际工作的应用中,Nginx跳转需求有三种方式可实现。可以直接用rewrite 进行匹配跳转,也可以使用if匹配全局变量后跳转。另外,还可以使用location 匹配再跳转。所以rewrite 只能放在 server、、location配置段中。例如 location 只能对域名后边的除去传递的参数外的字符串起作用,例如 htp://www.kgc.com/index.php?id=1 只对ndex.php 重写。如果想对域名或参数字符串起作用,可以使用i全局变量匹配,也可以使用 proxy_pass反向代理。
Rewrite 命令的语法如下所示,其中regex 表示正则匹配规则、replacement 表示跳转后的内容、fag 表示 rewrite 支持的 fag 标记。
falg标记说明
last : 相当于Apache的【L】标记,表示完成rewrite
break : 本条规则匹配完成即终止,不匹配后面的任何规则
如果后面不跟 fag 标记,那么默认是 302临时重定向。在实际工作场景中,还有另一种 return 指定。因为 301和 302 不能简单的只返回状态码,还必须有重定向的 URL,这就是 return 指令无法返回 301 和 302 的原因。
last 和 break 区别是: last 一般写在 server 和if中,而 break 一般使用在 location 中。last 不终止重写后的 ur 匹配,即新的 ur 会再从 server 走一遍匹配流程,而 break 终止重写后的匹配。
location 大致可以分为三类,语法如下:
location = patt {} [精准匹配]
location patt {} [一般匹配]
location ~ patt {} [正则匹配]
精准匹配和一般匹配不需要做详细的说明,主要是正则匹配。下面就是正则匹配的一些表达式,需要多加牢记。
~:表示执行一个正则匹配,区分大小写。
~*:表示执行一个正则匹配,不区分大小写。
》!~:表示执行一个正则匹配,区分大小写不匹配。
!~*:表示执行一个正则匹配,不区分大小写不匹配。
^~:表示普通字符匹配。使用前缀匹配。如果匹配成功,则不再匹配其他 location。
=:进行普通字符精确匹配,也就是完全匹配。
@:它定义一个命名的 location,使用在内部定向时,例如 error_page,try_files
在 Nginx 的 location 配置中 location 的顺序没有太大关系。匹配优先级和 location 表达式的类型有关:相同类型的表达式,字符串长的会优先匹配。
以下是按优先级排列说明:
等号类型(=)的优先级最高。一旦匹配成功,则不再查找其他匹配项。
^~类型表达式。一旦匹配成功,则不再查找其他匹配项。
正则表达式类型(~和~*)的优先级次之。
常规字符串匹配类型。按前缀匹配。
通用匹配(/),如果没有其它匹配,任何请求都会匹配到
很多情况下 rewrite 也会写在 location 里,它们的执行顺序如下:
(1) 执行 server 块里面的 rewrite 指令。
(2) 执行 location 匹配。
(3) 执行选定的 location 中的 rewrite 指令。
#精确匹配 / ,主机名后面不能带任何字符串
location = / {
[ configuration A ]
}
location / {
[ configuration B ]
}
location /documents/ {
[ configuration C ]
}
达式没有匹配到时,这一条才会起作用
location ~ /documents/abc {
[ configuration D ]
}
location ^~ /images/ {
[ configuration E ]
}
# 匹配所有以 gif,jpg 或 jpeg 结尾的请求,然而所有请求/images/下的图片会被 [ configuration E] 处理,因为^~的优先级更高
location ~* \.(gif|jpg|jpeg)$ {
[ configuration F ]
}
# 最长字符匹配到 /images/abc,优先级最低
location /images/abc {
[ configuration G ]
}
# 匹配以/images/abc 开头的,优先级次之
location ~ /images/abc {
[ configuration H ]
}
# 匹配/images/abc/1.html 文件,如果和正则~ /images/abc/1.html 相比,正则优先级更高
location /images/abc/1.html {
[ configuration I ]
}
总结:
如果是匹配某个具体文件
(location = 完整路径) > (location ^~ 完整路径) > (location ~* 完整路径)> (location ~ 完整路径) > (location 完整路径) > (location /)
192.168.10.101 www.benet.com
192.168.10.102 www.accp.com
设置好客户端和服务器端的hosts文件
要求:访问www.benet.com,跳转到www.accp.com
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name www.benet.com;
charset utf-8;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name www.benet.com;
charset utf-8;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
if ($host = 'www.benet.com')
{
rewrite ^/(.*)$ http://www.accp.com/$1 permanent;
}
}
}
备注:
$host = 'www.benet.com' 判断获取到得请求URL是否为www.benet.com 另外,=号两边有空格
^/(.*)$
^ 指的是以任何字符或字符串开始的域名都会匹配上
/ 指得是url后跟的/,比如www.benet.com/index.html
.* 匹配任意多个字符,注意这里的(),括号里的内容会用后面的$1调用
$ 结尾
备注:
Rewrite 语法
rewrite<regex><replacement>[flag];
flag 标记说明:
[root@localhost ~]# systemctl restart nginx //重启nginx服务
a:域名直接跳转
按 F12 可以清楚的看到从旧域名 www.benet.com 跳转到了新域名 www.accp.com 上,状态码是 301 永久重定向
b:域名后面加参数跳转
备注:
常见的正则表达式元字符
^ | 匹配输入字符串的起始位置 |
$ | 匹配输入字符串的结束位置 |
* | 匹配前面的字符零次或多次。如"ol*"能匹配"o"及"ol"、"oll |
+ | 匹配前面的字符一次或多次。如"ol+"能匹配"ol"及"oll,但不能匹配 o |
? | 匹配前面的字符零次或一次,例如"do(es)?"能匹配"do"或者"does","?"等效于"{0,y} |
. | 匹配除"n"之外的任何单个字符,若要匹配包括"n"在内的任意字符,请使用诸如"[.\n]"之类的模式 |
\ | 将后面接着的字符标记为一个特殊字符或一个原义字符或一个向后引用。如"\n"匹配一个换行符,而"\$"则匹配"$" |
\d | 匹配纯数字 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
[c] | 匹配单个字符c |
[a-z] | 匹配 a-z小写字母的任意一个 |
[a-zA-Z] | 匹配 a-z小写字母或A-Z大写字母的任意一个 |
备注:
匹配规则
~:表示执行一个正则匹配,区分大小写。
~*:表示执行一个正则匹配,不区分大小写。
!~:表示执行一个正则匹配,区分大小写不匹配。
!~*:表示执行一个正则匹配,不区分大小写不匹配。
^~:表示普通字符匹配。使用前缀匹配。如果匹配成功,则不再匹配其他 location。
=:进行普通字符精确匹配,也就是完全匹配。
@:它定义一个命名的 location,使用在内部定向时,例如 error_page, try_files。
要求所有外部IP访问任何内容都显示一个固定维护页面,只有公司内部IP 访问正常
假设内部IP为192.168.10.103,外部IP为192.168.10.105
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name www.benet.com;
#access_log /var/log/nginx/host.access.log main;
set $rewrite true;
if ($remote_addr = "192.168.10.51") {
set $rewrite false;
}
if ($rewrite = true) {
rewrite (.+) /maintenance.html;
}
location / {
root html;
index index.html index.htm;
# if ($host = 'www.benet.com')
# {
# rewrite ^/(.*)$ http://www.accp.com/$1 permanent;
# }
}
}
备注:
(.+) 匹配整个URL,匹配上以后,就在URL后面加上/maintenance.html
.+ 匹配任意字符1次或多次
.* 匹配任意字符0次或多次
[root@localhost ~]# systemctl restart nginx
[root@localhost ~]# echo "Website is Maintaining,Please visit later."> /usr/local/nginx/html/maintenance.html
先用客户端192.168.10.51访问,能正常访问www.benet.com,再用其他IP客户端访问,打开的是maintenance.html页面
访问http://bbs.benet.com/post时,需要将这个域名跳转到http://www.benet.com/bbs/post
[root@localhost html]# cd /usr/local/nginx/html/
[root@localhost html]# mkdir -p bbs/post
[root@localhost html]# cd bbs/post
[root@localhost post]# echo "i am bbs">index.html
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name bbs.benet.com;
#access_log /var/log/nginx/host.access.log main;
location /post {
rewrite (.+) http://www.benet.com/bbs$1 permanent;
}
location / {
root html;
index index.html index.htm;
}
}
[root@localhost ~]# systemctl restart nginx
客户端添加域名解析
192.168.10.101 bbs.benet.com
备注:
如果需要将bbs.benet.com的域名重写为www.benet.com/bbs
则使用如下配置:
server {
listen 80;
server_name bbs.benet.com;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
if ($host = 'bbs.benet.com')
{
rewrite ^/(.*)$ http://www.benet.com/bbs/$1 permanent;
}
}
}
在访问 http://www.benet.com/100-(100|200)-100.html 跳转到 http://www.benet.com页面
[root@localhost post]# vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name bbs.benet.com;
#access_log /var/log/nginx/host.access.log main;
if ($request_uri ~ ^/100-(100|200)-(\d+).html$) {
rewrite (.*) http://www.benet.com permanent;
}
location / {
root html;
index index.html index.htm;
}
备注:
\d+ 匹配任意个数字
[root@localhost ~]# systemctl restart nginx
使用浏览器访问 http://www.benet.com/100-100-100.html,会跳转到http://www.benet.com
要求访问 http://www.benet.com/upload/1.php跳转到首页
[root@localhost post]# vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name bbs.benet.com;
#access_log /var/log/nginx/host.access.log main;
location ~* /upload/.*\.php$ {
rewrite (.+) http://www.benet.com permanent;
}
location / {
root html;
index index.html index.htm;
}
}
备注:
~* 不区分大小写
~ 区分大小写
.*\.php 一个文件的名字 名字.后缀 任意名字.php
[root@localhost ~]# systemctl restart nginx
浏览器访问 http://www.benet.com/upload/1.php会跳转到http://www.benet.com
(6)基于最普通一条 url 请求的跳转
[root@localhost post]# vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name bbs.benet.com;
#access_log /var/log/nginx/host.access.log main;
location ~* ^/1/test.html {
rewrite (.+) http://www.benet.com permanent;
}
location / {
root html;
index index.html index.htm;
}
[root@localhost ~]# systemctl restart nginx
浏览器访问 http://www.benet.com/1/test.html 跳转到http://www.benet.com
以上就是几种常见的rewrite使用方式
因篇幅问题不能全部显示,请点此查看更多更全内容