文章目录
深入探索 Nginx 的 URL 重写与位置匹配
官方文档
一、Nginx 正则表达式基础
Nginx 正则表达式是用于匹配和重写 URL 的强大工具。下面是常用的 Nginx 正则表达式符号及其含义:
^
:匹配输入字符串的起始位置。$
:匹配输入字符串的结束位置。*
:匹配前面的字符零次或多次。如“ol*”能匹配“o”及“ol”、“oll”。+
:匹配前面的字符一次或多次。如“ol+”能匹配“ol”及“oll”、“olll”,但不能匹配“o”。?
:匹配前面的字符零次或一次,例如“od(es)?”能匹配“do”或者“does”,”?”等效于”{0,1}”。.
:匹配除“\n”之外的任何单个字符,若要匹配包括“\n”在内的任意字符,请使用诸如“[.\n]”之类的模式。\
:将后面接着的字符标记为一个特殊字符或一个原义字符或一个向后引用。如“\n”匹配一个换行符,而“$”则匹配“$”。\d
:匹配纯数字。{n}
:重复 n 次。{n,}
:重复 n 次或更多次。{n,m}
:重复 n 到 m 次。[]
:定义匹配的字符范围。[c]
:匹配单个字符 c。[a-z]
:匹配 a-z 小写字母的任意一个。[a-zA-Z0-9]
:匹配所有大小写字母或数字。()
:表达式的开始和结束位置。|
:或运算符。
二、rewrite 和 location 的区别
从功能上看,rewrite
和 location
似乎都有实现跳转的能力。主要区别在于 rewrite
是在同一域名内更改获取资源的路径,而 location
是对一类路径进行访问控制或反向代理,还可以通过 proxy_pass
将请求代理到其他机器。
三、rewrite 指令详解
rewrite
功能就是使用 Nginx 提供的全局变量或自定义变量,结合正则表达式和标记位实现 URL 重写及重定向。常见的应用场景包括域名变更后的跳转、网页地址更改后的跳转以及网站防盗链等。
rewrite
指令只能放在 server{}
, location{}
, if{}
块中,并且默认只能对域名后面的路径进行重写,不包括传递的参数。例如,http://www.kgc.com/abc/bbs/index.php?a=1&b=2
只会对 /abc/bbs/index.php
进行重写。
四、rewrite 跳转实现
Nginx 通过 ngx_http_rewrite_module
模块支持 URL 重写和 if
条件判断,但不支持 else
。跳转时,从一个 location
跳转到另一个 location
的次数最多为 10 次,超过后 Nginx 将返回 500 错误。该模块还支持 Perl 兼容正则表达式的语法规则匹配,以及通过 set
指令创建新变量并赋值。
rewrite
执行顺序如下:
- 执行
server
块里面的rewrite
指令。 - 执行
location
匹配。 - 执行选定的
location
中的rewrite
指令。
五、rewrite 语法格式及 flag 说明
语法格式:
rewrite <regex> <replacement> [flag];
regex
:表示正则匹配规则。replacement
:表示跳转后的内容。flag
:表示rewrite
支持的标记。
flag 标记说明
last
:本条规则匹配完成后,继续向下匹配新的location
URL 规则,一般用在server
和if
中。break
:本条规则匹配完成即终止,不再匹配后面的任何规则,一般使用在location
中。redirect
:返回 302 临时重定向,浏览器地址会显示跳转后的 URL 地址。permanent
:返回 301 永久重定向,浏览器地址栏会显示跳转后的 URL 地址。
六、location 指令详解
location
大致可以分为三类:
- 精准匹配:
location = / {...}
- 一般匹配:
location / {...}
- 正则匹配:
location ~ / {...}
location 常用的匹配规则
=
:进行普通字符精确匹配,完全匹配时触发。^~
:表示普通字符匹配,使用前缀匹配。如果匹配成功,则不再匹配其它location
。~
:区分大小写的正则匹配。~*
:不区分大小写的正则匹配。!~
:区分大小写的匹配取非。!~*
:不区分大小写的匹配取非。
location 优先级
- 首先精确匹配
=
- 其次前缀匹配
^~
- 按文件中顺序的正则匹配
~
或~*
- 匹配不带任何修饰的前缀匹配
- 最后交给
/
通用匹配
七、location 示例说明
7.1 示例 1:精准匹配
location = /
精确匹配根路径,通常用于处理网站的首页访问。此规则优先级最高,只要请求的路径完全匹配 /
,就会触发此规则。
7.2 示例 2:一般匹配
location / {}
匹配所有以 /
开头的请求,这是一个最为通用的匹配规则,但优先级较低。
7.3 示例 3:正则匹配
location ~* \.(gif|jpg|jpeg)$ {}
匹配所有以 .gif
、.jpg
或 .jpeg
结尾的请求。此规则适用于需要区分文件类型的情况。
八、location 匹配优先级总结
- 精确匹配优先级最高
- 其次是
^~
前缀匹配 - 正则匹配(
~
、~*
)次之 - 最后是通用的
/
匹配
九、rewrite 实际应用示例
9.1 基于域名的跳转
旧域名 www.kgc.com
需要跳转到新域名 www.benet.com
,可以使用以下配置:
server {
listen 80;
server_name www.kgc.com;
if ($host = 'www.kgc.com'){
rewrite ^/(.*)$ http://www.benet.com/$1 permanent;
}
root html;
index index.html index.htm;
}
9.2 基于客户端 IP 访问跳转
所有 IP 访问显示维护页面,只有公司 IP 192.168.10.19
可以正常访问:
server {
listen 80;
server_name www.kgc.com;
set $rewrite true;
if ($remote_addr = "192.168.10.19"){
set $rewrite false;
}
if ($rewrite = true){
rewrite (.+) /weihu.html;
}
location = /weihu.html {
root /var/www/html;
}
location / {
root html;
index index.html index.htm;
}
}
9.3 基于旧域名跳转到新域名加目录
旧域名 bbs.kgc.com/post/
需要跳转到新域名 www.kgc.com/bbs/post/
:
server {
listen 80;
server_name bbs.kgc.com;
location /post {
rewrite (.+) http://www.kgc.com/bbs$1 permanent;
}
location / {
root html;
index index.html index.htm;
}
}
9.4 基于参数匹配的跳转
访问 `http://www.kgc.com/100-(100
|200)-100.html跳转到
http://www.kgc.com`:
server {
listen 80;
server_name www.kgc.com;
if ($request_uri ~ ^/100-(100|200)-(\d+).html$) {
rewrite (.+) http://www.kgc.com permanent;
}
location / {
root html;
index index.html index.htm;
}
}
9.5 基于目录下所有 php 结尾的文件跳转
访问 http://www.kgc.com/upload/123.php
跳转到首页:
server {
listen 80;
server_name www.kgc.com;
location ~* /upload/.*\.php$ {
rewrite (.+) http://www.kgc.com permanent;
}
location / {
root html;
index index.html index.htm;
}
}
9.6 基于最普通一条 URL 请求的跳转
访问 http://www.kgc.com/abc/123.html
跳转到首页:
server {
listen 80;
server_name www.kgc.com;
location ~* ^/abc/123.html {
rewrite (.+) http://www.kgc.com permanent;
}
location / {
root html;
index index.html index.htm;
}
}
80;
server_name www.kgc.com;
location ~* ^/abc/123.html {
rewrite (.+) http://www.kgc.com permanent;
}
location / {
root html;
index index.html index.htm;
}
}