【NGINX入门】6.Nginx的rewrite规则详解

1.摘要

nginx Rewrite规则可以让网站的url中达到某种状态时定向/跳转到某个规则,本文具体介绍这些规则和说明。

2. 内容

2.1 Rewrite规则

rewrite功能就是,使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向。rewrite只能放在server{}, location{}, if{}中,并且只能对域名后边的除去传递的参数外的字符串起作用,例如 http://seanlook.com/a/we/index.php?id=1&u=str 只对/a/we/index.php重写。

语法:

rewrite regex replacement [flag];

如果相对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用proxy_pass反向代理。

表面看rewrite和location功能有点像,都能实现跳转,主要区别在于rewrite是在同一域名内更改获取资源的路径,而location是对一类路径做控制访问或反向代理,可以proxy_pass到其他机器。很多情况下rewrite也会写在location里,它们的执行顺序是:

  • 1,执行server块的rewrite指令
  • 2,执行location匹配
  • 3,执行选定的location中的rewrite指令

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

2.2 flag标志位

  • last : 相当于Apache的[L]标记,表示完成rewrite
  • break : 停止执行当前虚拟主机的后续rewrite指令集
  • redirect : 返回302临时重定向,地址栏会显示跳转后的地址
  • permanent : 返回301永久重定向,地址栏会显示跳转后的地址
(1)break和last区别

rewrite里面flag中break和last是什么区别?请看下面的例子:

root /opt/app/code; 

location ~ ^/break {
    rewrite ^/break /test/ break;
} 

location ~ ^/last {
     rewrite ^/last /test/ last;
}    

location /test/ {
   default_type application/json;
   return 200 '{"status":"success"}';
}

break是停止处理当前的ngx_http_rewrite_module指令集,就是说不会在向下匹配新的location,last停止处理当前的ngx_http_rewrite_module指令集并开始搜索与更改的URI匹配的新位置;

假设我们在页面上访问的url是http://walidream.com/break,根据上面的nginx规则,肯定会匹配到第一个,匹配到第一个之后,根据rewrite正则,url由原来的/break变为/test/但是在root/opt/code/目录下,没有找到/test/目录下面的内容,所以nginx会返回404错误码。

如果将http://walidream.com/break换成http://walidream.com/last,根据上面的nginx规则,会匹配到第二个location,根据location里面rewrite正则,url由原来的/last变为/test/,但是会重新
匹配loction中,可以简单理解就是将替换后urlhttp://walidream.com/test重新发起一次请求。这个时候会匹配到第三个loaction,根据location里的rewrite正则,会返回200码,并且会返回json内容’{“status”:“success”}’。

总结说明下:

  • last一般写在server和if中,而break一般使用在location中;
  • last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配;
  • break和last都能组织继续执行后面的rewrite指令;
(2)redirect和permanent区别

rewrite里面flag中redirect(临时重定向)和permanent(永久重定向)是什么区别?请看下面的例子:

location ~ ^/imooc { 
    rewrite ^/imooc http://www.imooc.com/ redirect;
} 

location ~ ^/wali {
    rewrite ^/wali http://www.imooc.com/ permanent;
}

redirect会返回带有302代码的临时重定向,permanent会返回带有301代码的永久重定向。

假设我们在页面上访问url是http://walidream.com/imooc,根据nginx匹配规则会匹配到第一个location,会重写url,返回一个带有302状态代码,重写后的url是http://www.imooc.com,浏览器会重定向到这个网址,
当我们再次访问http://walidream.com/imooc,nginx还是会先匹配再替换然后重定向。

如果在页面上输入http://walidream.com/wali,根据nginx匹配规则会匹配到第二个location,会重写url,返回一个带有301状态码,重写后的url是http://www.imooc.com,浏览器会重新定向到这个网址,
当我们再次访问http://walidream.com/wali,这个时候浏览器根本不会在经过nginx,而是直接有浏览器重定向到这个网址。

2.3 全局变量

内置的全局变量如下。

变量名 描述
$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,$uri不包含主机名,如”/foo/bar.html”
$document_uri 与$uri相同

2.4 if指令与全局变量使用

if判断指令的语法

if (condition) { ... }

对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行,if条件(conditon)可以是如下任何内容:
(1) 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false
(2) 直接比较变量和内容时,使用=或!=
(3) 正则表达式匹配,*不区分大小写的匹配,!~区分大小写的不匹配
(4) -f和!-f用来判断是否存在文件
(5) -d和!-d用来判断是否存在目录
(6) -e和!-e用来判断是否存在文件或目录
(7) -x和!-x用来判断文件是否可执行

例如:​

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

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;
    } //防盗链
}
valid_referers 指令详解

该指令后面可以接 none blocked serevr_names string或者是正则表达式:

  • none 代表没有referer
  • blocked 代表有referer但是被防火墙或者是代理给去除了
  • string或者正在表达式 用来匹配referer

nginx会通过查看referer字段和valid_referers后面的referer列表进行匹配,如果匹配到了就invalid_referer字段值为0 否则设置该值为1。
现我为公司写出了实现这一功能的代码

valid_referers none blocked server_names;
if ($invalid_referer) {
 rewrite ^/ http://********.com/ redirect;
}

说明:
1.首先当我输入我要打开的网址的时候,因为是直接输入的没有referer所以匹配了valid_referers后面的none或者是blocked 所以invalid_referer值为0 所以不进行跳转.
当我是从这个网站里面的链接跳到该网站首页的时候 因为referer的值是肯定包含srever_names,所以匹配了server_names所以不进行跳转。

2.当我从搜素引擎进去的时候因为referer字段类似于www.google.com.hk/search开始进行匹配 发现没有一个匹配,则此时会设置invalid_referer值为1 if语句成功执行,进行了跳转. 达到功能。

2.4 调试rewrite是否正确

2.4.1 打开rewrite_log

nginx中要检测rewrite是否正确,就需要开启rewrite_log才能排错,rewrite_log会打印错误。检测完后,建议将rewrite_log关闭。

rewrite_log
Syntax: rewrite_log on | off;
Default: rewrite_log off;
Context: http, server, location, if

示例:

rewrite_log on;
error_log /var/log/nginx/rewrite.log notice;

2.4.2 利用变量或者return调试

一般来说,要验证rewrite正则是否正确,就要打开rewrite_log日志,如果匹配错了,日志会记录错误信息。
另外,一般的检测语法,我们可以利用变量return 返回。

location ~ ^/wali {
    default_type application/json;
    return 200 '{"status":"success"}';
}

location ~ ^/yagm {
    default_type application/json;
    return 200 '{"status":"error"}';
}

这样有时候在调试时会让我们变得稍微方便一点,还有nginx扩展模块如echo就能直接输出内容或者打印内部变量。

3. 参考

(1)Nginx系列教程之基于nginx配置请求转发location及rewrite规则详解
https://blog.csdn.net/JunyouYH/article/details/107469699

(2)nginx rewrite规则(23)
https://www.imooc.com/article/283363

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容