Nginx中的正则表达式

释放双眼,带上耳机,听听看~!

1、if指令

所有的Nginx内置变量都可以通过if指令和正则表达式来进行匹配,并且根据匹配结果进行一些操作,如下:


1
2
3
4
5
6
7
8
1if ($http_user_agent ~ MSIE) {
2  rewrite  ^(.*)$  /msie/$1  break;
3}
4
5if ($http_cookie ~* "id=([^;] +)(?:;|$)" ) {
6  set  $id  $1;
7}
8

使用符号~*和~模式匹配的正则表达式:

~为区分大小写的匹配。
1.
~*不区分大小写的匹配(匹配firefox的正则同时匹配FireFox)。
1.
!和!*意为“不匹配的”。

Nginx在很多模块中都有内置的变量,常用的内置变量在HTTP核心模块中,这些变量都可以使用正则表达式进行匹配。

2、可以通过正则表达式匹配的指令

location

可能这个指令是我们平时使用正则匹配用的最多的指令:


1
2
3
4
5
6
7
1location ~ .*\.php?$ {
2        fastcgi_pass   127.0.0.1:9000;
3        fastcgi_index  index.php;
4        fastcgi_param  SCRIPT_FILENAME  /data/wwwsite/test.com/$fastcgi_script_name;
5        include        fcgi.conf;
6    }
7

几乎每个基于LEMP的主机都会有如上一段代码。他的匹配规则类似于if指令,不过他多了三个标识符,^~、=、@。并且它没有取反运算符!,这三个标识符的作用分别是:

^~ 标识符后面跟一个字符串。Nginx将在这个字符串匹配后停止进行正则表达式的匹配(location指令中正则表达式的匹配的结果优先使用),如:location ^~ /images/,你希望对/images/这个目录进行一些特别的操作,如增加expires头,防盗链等,但是你又想把除了这个目录的图片外的所有图片只进行增加expires头的操作,这个操作可能会用到另外一个location,例如:location * .(gif|jpg|jpeg)$,这样,如果有请求/images/1.jpg,nginx如何决定去进行哪个location中的操作呢?结果取决于标识符^,如果你这样写:location /images/,这样nginx会将1.jpg匹配到location ~* .(gif|jpg|jpeg)$这个location中,这并不是你需要的结果,而增加了^~这个标识符后,它在匹配了/images/这个字符串后就停止搜索其它带正则的location。
1.
= 表示精确的查找地址,如location = /它只会匹配uri为/的请求,如果请求为/index.html,将查找另外的location,而不会匹配这个,当然可以写两个location,location = /和location /,这样/index.html将匹配到后者,如果你的站点对/的请求量较大,可以使用这个方法来加快请求的响应速度。
1.
@ 表示为一个location进行命名,即自定义一个location,这个location不能被外界所访问,只能用于Nginx产生的子请求,主要为 error_page和 try_files。

注意,这3个标识符后面不能跟正则表达式,虽然配置文件检查会通过,而且没有任何警告,但是他们并不会进行匹配。
综上所述,location指令对于后面值的匹配顺序为:

标识符“=”的location会最先进行匹配,如果请求uri匹配这个location,将对请求使用这个location的配置。
1.
进行字符串匹配,如果匹配到的location有^~这个标识符,匹配停止返回这个location的配置。
1.
按照配置文件中定义的顺序进行正则表达式匹配。最早匹配的location将返回里面的配置。
1.
如果正则表达式能够匹配到请求的uri,将使用这个正则对应的location,如果没有,则使用第二条匹配的结果。

server_name

server_name用于配置基于域名或IP的虚拟主机,这个指令也是可以使用正则表达式的,但是注意,这个指令中的正则表达式不用带任何的标识符,但是必须以~开头:


1
2
3
4
1server {
2  server_name   www.example.com   ~^www\d+\.example\.com$;
3}
4

server_name指令中的正则表达式可以使用引用,高级的应用可以查看这篇文章:在server_name中使用正则表达式

fastcgi_split_path_info

这个指令按照CGI标准来设置SCRIPT_FILENAME (SCRIPT_NAME)和PATH_INFO变量,它是一个被分割成两部分(两个引用)的正则表达式。如下:


1
2
3
4
5
6
7
8
9
1location ~ ^.+\.php {
2  (...)
3  fastcgi_split_path_info ^(.+\.php)(.*)$;
4  fastcgi_param SCRIPT_FILENAME /path/to/php$fastcgi_script_name;
5  fastcgi_param PATH_INFO $fastcgi_path_info;
6  fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
7  (...)
8}
9

第一个引用(.+.php)加上/path/to/php将作为SCRIPT_FILENAME,第二个引用(.*)为PATH_INFO,例如请求的完整URI为show.php/article/0001,则上例中SCRIPT_FILENAME的值为/path/to/php/show.php,PATH_INFO则为/article/0001。
这个指令通常用于一些通过PATH_INFO美化URI的框架(例如CodeIgniter)。

gzip_disable

通过正则表达式来指定在哪些浏览器中禁用gzip压缩。


1
2
1gzip_disable     "msie6";
2

rewrite

这个指令应该也是用的比较多的,它需要使用完整的包含引用的正则表达式:


1
2
1rewrite  "/photos/([0-9] {2})([0-9] {2})([0-9] {2})" /path/to/photos/$1/$1$2/$1$2$3.png;
2

通常环境下我们会把它和if结合来使用:


1
2
3
4
5
1if ($host ~* www\.(.*)) {
2  set $host_without_www $1;
3  rewrite ^(.*)$ http://$host_without_www$1 permanent; # $1为'/foo',而不是'www.mydomain.com/foo'
4}
5

需要注意的是rewrite后面的第一个正则参数永远是只对URI进行匹配,而不是对完整的带主机头的URL,如上例中,if语句来判断主机头,如果匹配www.(.*),则设置一个变量$host_without_www的值为www.(.*)的引用,如果上例中的请求URL为www.mydomain.com/foo,则$host_without_www的值为mydomain.com,而下面的rewrite指令中,第一个正则表达式的引用将为/foo,则最终通过这个重写后的请求URL为http://mydomain.com/foo。

3、Nginx中的正则如何匹配中文

首先确定在编译pcre时加了enable-utf8参数,如果没有,请重新编译pcre,然后就可以在Nginx的配置文件中使用这样的正则:”(*UTF8)^/[\x{4e00}-\x{9fbf}]+)$”注意引号和前面的(*UTF8),(*UTF8)将告诉这个正则切换为UTF8模式。

4、如何测试你的正则表达式

通常我们在Nginx安装之前会编译安装pcre,它自带一个小工具:pcretest,使用方法以下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1[root@backup conf]# pcretest
2PCRE version 8.10 2010-06-25
3
4  re> /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3,3}$/  ###这是一个匹配IP的正则
5data> 192.168.10.1
6 0: 192.168.10.1
7 1: 192
8 2: .1
9 3: 1
10data> 666.666.666.666
11No match
12data> 255.255.255.255
13 0: 255.255.255.255
14 1: 255
15 2: .255
16 3: 255
17data> 0.0.0.0
18 0: 0.0.0.0
19 1: 0
20 2: .0
21 3: 0
22data> 666777
23No match
24

匹配中文:


1
2
3
4
5
6
7
8
9
10
11
1[root@backup conf]# pcretest
2PCRE version 8.10 2010-06-25
3
4  re> /^[\x{4e00}-\x{9fbf}]+/8
5data> 测试
6 0: \x{6d4b}\x{8bd5}
7data> Nginx模块参考手册中文版
8No match
9data> 参考手册中文版
10 0: \x{53c2}\x{8003}\x{624b}\x{518c}\x{4e2d}\x{6587}\x{7248}
11

注意正则表达式后面的8,它表示这条正则使用UTF-8匹配。

Nginx 一些内置的变量


HTTP核心模块支持一些内置变量,变量名与apache里的对应。比如 $http_user_agent,$http_cookie等表示HTTP请求信息的变量。
更多变量:
$args, 请求中的参数;

$content_length, HTTP请求信息里的"Content-Length";

$content_type, 请求信息里的"Content-Type";

$document_root, 针对当前请求的根路径设置值;

$document_uri, 与$uri相同;

$host, 请求信息中的"Host",如果请求中没有Host行,则等于设置的服务器名;

$limit_rate, 对连接速率的限制;

$request_method, 请求的方法,比如"GET"、"POST"等;

$remote_addr, 客户端地址;

$remote_port, 客户端端口号;

$remote_user, 客户端用户名,认证用;

$request_filename, 当前请求的文件路径名

$request_body_file, ??

$request_uri, 请求的URI,带参数;

$query_string, 与$args相同;

$scheme, 所用的协议,比如http或者是https,比如rewrite  ^(.+)$  $scheme://example.com$1  redirect;

$server_protocol, 请求的协议版本,"HTTP/1.0"或"HTTP/1.1";

$server_addr, 服务器地址,如果没有用listen指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费);

$server_name, 请求到达的服务器名;

$server_port, 请求到达的服务器端口号;

$uri, 请求的URI,可能和最初的值有不同,比如经过重定向之类的。

 

给TA打赏
共{{data.count}}人
人已打赏
安全经验

如何避免Adsense违规封号

2021-10-11 16:36:11

安全经验

安全咨询服务

2022-1-12 14:11:49

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索