nginx 正则表达式使用的是PCRE,PCRE库是一组函数,它们使用与Perl 5相同的语法和语义实现正则表达式模式匹配.PCRE具有自己的本机API,以及一组与POSIX正则表达式API对应的包装函数。PCRE库是免费的,即使是用于构建专有软件。
PCRE最初是为Exim MTA编写的 ,但现在被许多备受瞩目的开源项目使用,包括 Apache, PHP, KDE, Postfix和 Nmap。PCRE还进入了一些着名的商业产品,如 Apple Safari。使用PCRE的其他一些有趣项目包括 Chicken, Ferite, Onyx, Hypermail, Leafnode, Askemos, Wenlin和 8th。
常用正则匹配符
- . : 匹配除换行符以外的任意字符
- ? : 重复0次或1次
- + : 重复1次或更多次
- * : 重复0次或更多次
- \d :匹配数字
- ^ : 匹配字符串的开始
- $ : 匹配字符串的介绍
- {n} : 重复n次
- {n,} : 重复n次或更多次
- [c] : 匹配单个字符c
- [a-z] : 匹配a-z小写字母的任意一个
注:小括号()之间匹配的内容,可以在后面通过$1来引用,$2表示的是前面第二个()里的内容。
正则表达式测试工具
- 在线测试工具
- linux 下的 grep 工具:grep -P 命令
$ echo 'a.gif' | grep -P '\.(jp?g|gif|bmp|png)'
#输出
a.gif
全局变量
* $args 请求中的参数;
* $binary_remote_addr 远程地址的二进制表示
* $body_bytes_sent 已发送的消息体字节数
* $content_length HTTP请求信息里的"Content-Length";
* $content_type 请求信息里的"Content-Type";
* $document_root 针对当前请求的根路径设置值;
* $document_uri 与$uri相同;
* $host 请求信息中的"Host",如果请求中没有Host行,则等于设置的服务器名;
* $hostname
* $http_cookie cookie 信息
* $http_post
* $http_referer 引用地址
* $http_user_agent 客户端代理信息
* $http_via 最后一个访问服务器的Ip地址。http://www.cnblogs.com/deng02/archive/2009/02/11/1387911.html
* $http_x_forwarded_for 相当于网络访问路径。http://www.cnblogs.com/craig/archive/2008/11/18/1335809.html
* $is_args
* $limit_rate 对连接速率的限制;
* $nginx_version
* $pid
* $query_string 与$args相同;
* $realpath_root
* $remote_addr 客户端地址;
* $remote_port 客户端端口号;
* $remote_user 客户端用户名,认证用;
* $request 用户请求
* $request_body
* $request_body_file 发往后端的本地文件名称
* $request_completion
* $request_filename 当前请求的文件路径名
* $request_method 请求的方法,比如"GET"、"POST"等;
* $request_uri 请求的URI,带参数;
* $scheme 所用的协议,比如http或者是https,比如rewrite^(.+)$$scheme://example.com$1redirect;
* $sent_http_cache_control
* $sent_http_connection
* $sent_http_content_length
* $sent_http_content_type
* $sent_http_keep_alive
* $sent_http_last_modified
* $sent_http_location
* $sent_http_transfer_encoding
* $server_addr 服务器地址,如果没有用listen指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费);
* $server_name 请求到达的服务器名;
* $server_port 请求到达的服务器端口号;
* $server_protocol 请求的协议版本,"HTTP/1.0"或"HTTP/1.1";
* $uri 请求的URI,可能和最初的值有不同,比如经过重定向之类的。
HttpRewrite模块
该模块允许使用正则表达式改变URI,并且根据变量来转向以及选择配置。如果在server级别设置该选项,那么他们将在location之前生效。如果在location还有更进一步的重写规则,location部分的规则依然会被执行。如果这个URI重写是因为location部分的规则造成的,那么location部分会再次被执行作为新的URI
break 指令
语法 break
作用域:server,location,if
作用是完成当前的规则列
示例
if ($slow) {
: limit_rate 10k;
: break;
}
if 指令
if判断指令
语法为if(condition){…},对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行,if条件(conditon)可以是如下任何内容:
作用域: server, location
- 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false
- 直接比较变量和内容时,使用=或!=
- 正则表达式匹配,*不区分大小写的匹配,!~区分大小写的不匹配
-f和!-f用来判断是否存在文件
-d和!-d用来判断是否存在目录
-e和!-e用来判断是否存在文件或目录
-x和!-x用来判断文件是否可执行
示例
if ($http_user_agent ~ MSIE) {
: rewrite ^(.*)$ /msie/$1 break;
}
if ($http_cookie ~* "id=([^;] +)(?:;|$)" ) {
: set $id $1;
}
if ($request_method = POST ) {
: return 405;
}
if (!-f $request_filename) {
: break;
: proxy_pass http://127.0.0.1;
}
if ($slow) {
: limit_rate 10k;
}
if ($invalid_referer) {
: return 403;
}
return指令
语法:return code
作用域: server, location, if
这个指令根据规则的执行情况,返回一个状态值给客户端。可使用值包括:204,400,402-406,408,410,411,413,416以及500-504。也可以发送非标准的444代码-未发送任何头信息下结束连接
rewrite指令
语法: rewrite regex replacement flag
默认: none
作用域: server, location, if
这个指令根据表达式来更改URI,或者修改字符串。指令根据配置文件中的顺序来执行。
注意重写表达式只对相对路径有效。如果你想配对主机名,你应该使用if语句,如下
if ($host ~* www\.(.*)) {
: set $host_without_www $1;
: rewrite ^(.*)$ http://$host_without_www$1 permanent; # $1 contains '/foo', not 'www.mydomain.com/foo'
}
需要注意的是rewrite后面的第一个正则参数永远是只对URI进行匹配,而不是对完整的带主机头的URL,如上例中,if语句来判断主机头,如果匹配www.(.*),则设置一个变量KaTeX parse error: Can't use function '\.' in math mode at position 23: …thout_www的值为www\̲.̲(.*)的引用,如果上例中的请…host_without_www的值为mydomain.com,而下面的rewrite指令中,第一个正则表达式的引用将为/foo,则最终通过这个重写后的请求URL为http://mydomain.com/foo
location ~* ^/static/.*\.jpg$ {
root /usr/share/nginx/html/;
rewrite /static/css/(.*)$ /$1 ;
}
匹配/static/开头,.jpg 结尾的请求中,将所有/static/css/开头的请求去掉/static/css
- 示例三
nginx rewrite 实现二级域名跳转
当访问http://abc.jbxue.com跳转到http://www.jbxue.com/test/abc/
方法一:这种方法浏览器地址会变www.jbxue.com/test/abc
server {
listen 80;
server_name www.jbxue.com;
location / {
root /data/test;
index index.html;
}
}
server {
listen 80;
server_name *.jbxue.com;
if ( $http_host ~* "^(.*)\.jbxue\.com$") {
set $domain $1;
rewrite ^(.*) http://www.jbxue.com/test/$domain/ break;
}
}
方法二:当访问http://abc.jbxue.com跳转到http://www.jbxue.com/test/abc/
server {
listen 80;
server_name *.jbxue.com;
root /usr/local/www;
#这是里可以加多个目录,如果不加目录,会无法访问到abc.jbxue.com/目录下的文件,如图片目录/images
location ~ ^/(jbxue|images|styles)/
{
proxy_redirect off;
proxy_set_header Host www.jbxue.com;
proxy_pass http://192.168.1.2:8080;
}
location / {
set $domain default;
if ( $http_host ~* "^(.*)\.jbxue\.com$") {
set $domain $1;
}
rewrite ^/(.*) /test/$domain/$1 last;
}
access_log off;
}
标志位
- last : 相当于Apache的[L]标记,表示完成rewrite
- break : 停止执行当前虚拟主机的后续rewrite指令集
- redirect : 返回302临时重定向,地址栏会显示跳转后的地址
- permanent : 返回301永久重定向,地址栏会显示跳转后的地址
因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return指令无法返回301,302的原因了。这里 last 和 break 区别有点难以理解:
- last一般写在server和if中,而break一般使用在location中
- last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配
- break和last都能组织继续执行后面的rewrite指令
set 指令
语法:设置变量值
作用域:server,location,if
指令为指示的变量建立值。 作为值,可以使用文本,变量及其组合