Nginx 重写规则(rewrite rule)

这里不讨论rewrite中的配置, 不讨论nginx的其他配置

rewrite: 使用nginx提供的全局变量或自定义变量,结合正则表达式和标志位实现url重写以及重定向。

rewrite只能放在配置文件的server{ },location{},if{}中,并且只能对域名后面(或者叫路径, 不包含请求参数(query string))的字符串起作用。

例如: http://www.domain.com/a/b/index.html?id=1&page=2 只对 /a/b/index.html 重写。

如果想对域名或请求参数(query string)起作用,可使用全局变量匹配,也可以使用proxy_pass反向代理。

  • 语法:rewrite regex replacement [flag];
  • 默认值:无
  • 作用域:server,location,if

如果一个URI匹配指定的正则表达式regexURI就按照replacement重写。

rewrite按配置文件中出现的顺序执行,flags标志可以停止继续处理。

如果replacement以 "http://" 或 "https://" 开始,将不再继续处理,这个重定向将返回给客户端。

rewrite指令执行顺序

  1. 执行server块的rewrite指令(这里的块指的是server关键字后{}包围的区域,其它xx块类似)
  2. 执行location匹配
  3. 执行选定的location中的rewrite指令

如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件;循环超过10次,则返回500 Internal Server Error错误。

rewritelocation功能有点像,都能实现跳转,区别在于:

  • rewrite 是在同一域名内更改获取资源的路径
  • location 是对一类路径做控制访问或反向代理,可以proxy_pass到其他机器。

很多情况下rewrite也会写在location里.

rewrite实例:

server {
     ...
     rewrite ^(/download/.*)/media/(.*)..*$ $1/mp3/$2.mp3 last;
     rewrite ^(/download/.*)/audio/(.*)..*$ $1/mp3/$2.ra last;
     return 403;
     ...
}

如果这些rewrite放到 “/download/” location 如下所示, 那么应使用break而不是last , 使用last将循环10次匹配,然后返回 500错误:

 location /download/ {
     rewrite ^(/download/.*)/media/(.*)..*$ $1/mp3/$2.mp3 break;
     rewrite ^(/download/.*)/audio/(.*)..*$ $1/mp3/$2.ra break;
     return 403;
 }

对于重写后的 URLreplacement)包含原请求的请求参数(query string),即原URL?后的内容。如果不想带原请求的参数 ,可以在replacement后加一个问号。如下,我们加了一个自定义的参数user=$1, 然后在结尾处放了一个问号?, 把原请的参数去掉:

rewrite ^/users/(.*)$ /show?user=$1? last;

flag 标志位

flag可以是如下参数:

  • last 停止处理后续rewrite指令集,然后对当前重写的新URIrewrite指令集上重新查找。相当于Apache[L]标记
  • break 停止处理后续rewrite指令集,并不再重新查找, 但是当前location内剩余非rewrite语句和location外的的非rewrite语句可以执行。
  • redirect 如果replacement不是以"http://" 或 "https://" 开头,返回302临时重定向,地址栏会显示跳转后的地址
  • permant 返回301永久重定向,地址栏会显示跳转后的地址

rewritelastbreak的区别:

  • last一般写在serverif段中,而break一般使用在location段中
  • last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配
  • breaklast都能组织继续执行后面的rewrite指令

最终完整的重定向URL包括请求scheme(http://, https:// 等), 请求的server_name_in_redirectport_in_redirec三部分 ,说白了也就是http协议 域名 端口三部分组成。

if指令与全局变量

if指令

语法:if(condition){...}

默认值:无

作用域:server, location

对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行。

if条件(conditon)可以是如下任何内容:

  • 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做 (bool)false
  • 直接比较变量和内容时,使用 =!=
  • ~正则表达式匹配,~* 不区分大小写的匹配,!~ 区分大小写的不匹配. 如果这个正则表达式中包含} , ;则整个表达式需要用双引号" 或 单引号' 包围
  • -f!-f 用来判断是否存在文件
  • -d!-d 用来判断是否存在目录
  • -e!-e 用来判断是否存在文件或目录
  • -x!-x 用来判断文件是否可执行

e.g:

if ($http_user_agent ~ MSIE) {
    rewrite ^(.*)$ /msie/$1 break;
} //如果UA包含"MSIE",rewrite请求到/msid/目录下

if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
    set $id $1;
 } //如果cookie匹配正则,设置变量$id等于正则引用部分

if ($request_method = POST) {
    return 405;
} //如果提交方法为POST,则返回状态405(Method not allowed)。return不能返回301,302

if ($slow) {
    limit_rate 10k;
} //限速,$slow可以通过 set 指令设置

if (!-f $request_filename){
    break;
    proxy_pass  http://127.0.0.1; 
} //如果请求的文件名不存在,则反向代理到localhost 。这里的break会停止rewrite检查

if ($args ~ post=140){
    rewrite ^ http://example.com/ permanent;
} //如果query string中包含"post=140",永久重定向到example.com

location ~* \.(gif|jpg|png|swf|flv)$ {
    valid_referers none blocked www.jefflei.com www.leizhenfang.com;
    if ($invalid_referer) {
        return 404;
    } //防盗链
}

全局变量

  • $args : 请求参数,同$query_string
  • $content_length : 请求头中的Content-length字段。
  • $content_type : 请求头中的Content-Type字段。
  • $document_root : 当前请求在root指令中指定的值。
  • $host : 请求主机头字段,否则为服务器名称。
  • $http_user_agent : 客户端agent信息
  • $http_cookie : 客户端cookie信息
  • $limit_rate : 限制连接速率。
  • $request_method : 客户端请求的动作,通常为GET或POST。
  • $remote_addr : 客户端的IP地址。
  • $remote_port : 客户端的端口。
  • $remote_user : 已经经过Auth Basic Module验证的用户名。
  • $request_filename : 当前请求的文件路径,由root或alias指令与URI请求生成。
  • $scheme : HTTP方法(如http,https)。
  • $server_protocol : 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
  • $server_addr : 服务器地址,在完成一次系统调用后可以确定这个值。
  • $server_name : 服务器名称。
  • $server_port : 服务器的端口号。
  • $request_uri : 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
  • $uri : 不包含主机名和请求参数的当前URI,如”/foo/bar.html”。
  • $document_uri : 与$uri相同。

正则匹配

  • . : 匹配除换行符以外的任意字符
  • ? : 重复0次或1次
  • + : 重复1次或更多次
  • * : 重复0次或更多次
  • {n} : 重复n次
  • {n,} : 重复n次或更多次
  • \d :匹配数字
  • ^ : 匹配字符串的开始
  • $ : 匹配字符串的介绍
  • [c] : 匹配单个字符c
  • [a-zA-Z0-9] : 匹配a-z小写字母,A-Z大写字母, 数字0-9 中的任意一个
  • (jpg|png) : 匹配字符串 jpg 或 png , 括号表示分组

小括号()之间匹配的内容,可以在后面通过$1来引用,$2表示的是前面第二个()里的内容

rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$' /data?file=$3.$4;
# 注意不能在上面这条规则后面加上“last”参数,否则下面的set指令不会执行
set $file_name_without_ext $3;
set $file_ext $4;

对形如 /images/ef/202103/test.png 的请求,重写到 /data?file=test.png

rewrite规则中如果要忽略大小写, 可以使用 (?i)

这个与用"/"开始结尾的javascript/php等语言的reg pattern使用/i是不同的.

rewrite ^(.*)_(middle|small)(\.(?i)(jpg|jpeg|png|gif))$ /thumb_fixed.php break;

这个规则把 xxx_middle.jpg, xxx_middle.JPG, xxx_small.png, xxx_small.PNG 这样的图片地址进行了重写

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章