nginx rewrite执行顺序

本贴最后更新于 3253 天前,其中的信息可能已经时过境迁

Rewrite( URL 重写)指令可以出现在 server{} 下,也可以出现在 location{} 下,它们之间是有区别的!

对于出现在 server{} 下的 rewrite 指令,它的执行会在 location 匹配之前;

对于出现在 location{} 下的 rewrite 指令,它的执行当然是在 location 匹配之后,但是由于 rewrite 导致 HTTP 请求的 URI 发生了变化,所以 location{} 下的 rewrite 后的 URI 又需要重新匹配 location ,就好比一个新的 HTTP 请求一样(注意由 location{} 内的 rewrite 导致的这样的循环匹配最多不超过 10 次,否则 nginx 会报 500 错误)。

总的来说,如果 server{} 和 location{} 下都有 rewrite ,依然是先执行 server{} ,然后进行 location 匹配,如果被匹配的 location{} 之内还有 rewrite 指令,那么继续执行 rewrite ,同时因为 location{} 内的 rewrite 改变了 URI ,那么重写后的结果 URI 需要当做一个新的请求,重新匹配 location (应该也包括重新执行 server{} 下的 rewrite 吧)。

Last 与 break flag 的区别

关于 last flag 和 break flag 的区别,官方文档的描述是:“ last - completes processing of rewrite directives, after which searches for corresponding URI and location ”和“ break - completes processing of rewrite directives ”,都有“不让继续执行后面的 rewrite 指令”的含义,但是两者的区别并没有展开。

这里我用实验来告诉大家区别。实验准备:

1、  安装 nginx ;(如果对安装和 location 不了解的,请参考: http://eyesmore.iteye.com/blog/1141660 )

 

2、  在 nginx 安装目录的 html 子目录下创建 4 个文件,分别叫: aaa.html , bbb.html , ccc.html 和 ddd.html ,文件内容分别是各自的文件名(例 aaa.html 文件内容不妨写 aaa html file )。

3、  Nginx 配置文件初始化是:

 

error_log  logs/error.log info;  #URL 重写模块的日志会写入此文件

 

   server {

        listen       9090;

        server_name  localhost;

        root html;

        rewrite_log on;   # 打开 URL 重写模块的日志开关,以便写入 error_log

   

        location  /aaa.html {

            rewrite "^/aaa\.html$"  /bbb.html;

            rewrite "^/bbb\.html$"  /ddd.html;

        }  

   

        location  /bbb.html {

            rewrite "^/bbb\.html$" /ccc.html;

        }  

}

上述配置注意两点: 1 、打开 rewrite 模块的日志开关,以便 rewrite 执行日志写入 error_log (注: rewrite 日志写入 error_log 的级别是 notice ,所以要注意 error_log 日志级别,此处用 info ); 2 、定义了两个 location ,分别是 /aaa.html 和 /bbb.html ,但是在 /aaa.html 中,把 /aaa.html 重写成 /bbb.html ,接着又把 /bbb.html 重写成 /ddd.html ;在 /bbb.html 中,把 /bbb.html 重写成 /ccc.html 。

 

[ 测试 1] 没有 last 和 break 标记时:请求 aaa.html

[root@web108 ~]# curl http://localhost:9090/aaa.html

ddd html file

[root@web108 ~]#

Error_log 的日志内容:

2011/08/07 22:13:23 [notice] 9066#0: *85 "^/aaa\.html$" matches "/aaa.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:13:23 [notice] 9066#0: *85 rewritten data: "/bbb.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:13:23 [notice] 9066#0: *85 "^/bbb\.html$" matches "/bbb.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:13:23 [notice] 9066#0: *85 rewritten data: "/ddd.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:13:23 [info] 9066#0: *85 client 127.0.0.1 closed keepalive connection

 

URL 重写模块的日志告诉我们:对于一个 HTTP 请求“ GET /aaa.html ”,重写过程是:先 /aaa.html 被重写为 /bbb.html ;然后 rewritten data: /bbb.html ,继续执行后面的 rewrite 指令,进而被重写为 /ddd.html ,然后 rewrittern data: /ddd.html 后面没有重写了(其实此时 /ddd.html 需要再次重新匹配 location 的,只是日志没有体现出来,接下来的测试 2 会体现这点),于是输出 /ddd.html 的内容。

 

[ 测试 2] 使用 last 标记时:请求 aaa.html

将上述 location /aaa.html {} 修改成:

location  /aaa.html {

       rewrite "^/aaa\.html$"  /bbb.html   last ;

      rewrite "^/bbb\.html$"  /ddd.html;

}  

 

测试结果:

[root@web108 ~]# curl http://localhost:9090/aaa.html

ccc html file

[root@web108 ~]#

 

Error_log 日志:

2011/08/07 22:24:31 [notice] 18569#0: *86 "^/aaa\.html$" matches "/aaa.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:24:31 [notice] 18569#0: *86 rewritten data: "/bbb.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:24:31 [notice] 18569#0: *86 "^/bbb\.html$" matches "/bbb.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:24:31 [notice] 18569#0: *86 rewritten data: "/ccc.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:24:31 [info] 18569#0: *86 client 127.0.0.1 closed keepalive connection

 

不知道读者看到 GET /aaa.html 显示的结果“ ccc html file ”会不会惊讶:“为什么结果不是 bbb html file ”。下面解释下整个过程:首先 /aaa.html 匹配了 location /aaa.html {} ,于是执行 rewrite "^/aaa\.html$"  /bbb.html last ,把 /aaa.html 重写为 /bbb.html ,同时由于 last flag 的使用,后面的 rewrite 指令(指的是 rewrite "^/bbb\.html$"  /ddd.html )不会被执行。似乎此时应该输出“ bbb html file ”才对,但是我们看看 nginx 官方解释:“ last - completes processing of rewrite directives, after which searches for corresponding URI and location ”意思是说 last 不再匹配后面的 rewrite 指令,但是紧接着需要对重写后的 URI 重新匹配 location 。让我们再看看官方的“ If the directives of this module are given at the server level, then they are carried out before the location of the request is determined. If in that selected location there are further rewrite directives, then they also are carried out. If the URI changed as a result of the execution of directives inside location, then location is again determined for the new URI. This cycle can be repeated up to 10 times, after which Nginx returns a 500 error. ”因此,重新匹配的时候,匹配到了新的 location /bbb.html {} ,执行“ rewrite "^/bbb\.html$" /ccc.html ”,最后的内容是“ ccc html file ”。

 

[ 测试 3] 使用 break 标记时:请求 aaa.html

将上述 location /aaa.html {} 修改成使用 break 标记:

location  /aaa.html {

      rewrite "^/aaa\.html$"  /bbb.html  break ;

      rewrite "^/bbb\.html$"  /ddd.html;

}  

测试结果:

[root@web108 ~]# curl http://localhost:9090/aaa.html

bbb html file

[root@web108 ~]#

 

日志结果:

2011/08/07 22:37:49 [notice] 21069#0: *89 "^/aaa\.html$" matches "/aaa.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:37:49 [notice] 21069#0: *89 rewritten data: "/bbb.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:37:49 [info] 21069#0: *89 client 127.0.0.1 closed keepalive connection

 

我想这个结果不用多做解释了,充分体现了 break 和 last 的区别:“ last - completes processing of rewrite directives, after which searches for corresponding URI and location ”和“ break - completes processing of rewrite directives ”。 Break 和 last 都能阻止继续执行后面的 rewrite 指令,但是 last 如果在 location 下用的话,对于重写后的 URI 会重新匹配 location ,但是 break 则不会重新匹配 location 。简单的说, break 终止的力度比 last 更加彻底(为了记忆的方便,我们可以把重新后的 URI 重新匹配 location 理解为“ URI 匹配 location 的循环语句的下一次迭代”,高级程序设计里面 break 一般用做退出循环,所以 break 不仅终止继续执行 rewrite ,而且退出 URI 重新匹配 location 的循环迭代)。

  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    313 引用 • 547 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 工具

    子曰:“工欲善其事,必先利其器。”

    288 引用 • 734 回帖 • 1 关注
  • 游戏

    沉迷游戏伤身,强撸灰飞烟灭。

    177 引用 • 816 回帖
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 440 关注
  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 604 关注
  • Windows

    Microsoft Windows 是美国微软公司研发的一套操作系统,它问世于 1985 年,起初仅仅是 Microsoft-DOS 模拟环境,后续的系统版本由于微软不断的更新升级,不但易用,也慢慢的成为家家户户人们最喜爱的操作系统。

    223 引用 • 474 回帖
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 588 回帖
  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1435 引用 • 10056 回帖 • 489 关注
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    156 引用 • 3792 回帖 • 1 关注
  • 锤子科技

    锤子科技(Smartisan)成立于 2012 年 5 月,是一家制造移动互联网终端设备的公司,公司的使命是用完美主义的工匠精神,打造用户体验一流的数码消费类产品(智能手机为主),改善人们的生活质量。

    4 引用 • 31 回帖
  • Electron

    Electron 基于 Chromium 和 Node.js,让你可以使用 HTML、CSS 和 JavaScript 构建应用。它是一个由 GitHub 及众多贡献者组成的活跃社区共同维护的开源项目,兼容 Mac、Windows 和 Linux,它构建的应用可在这三个操作系统上面运行。

    15 引用 • 136 回帖 • 1 关注
  • Angular

    AngularAngularJS 的新版本。

    26 引用 • 66 回帖 • 536 关注
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖 • 1 关注
  • IDEA

    IDEA 全称 IntelliJ IDEA,是一款 Java 语言开发的集成环境,在业界被公认为最好的 Java 开发工具之一。IDEA 是 JetBrains 公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

    181 引用 • 400 回帖
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    2 引用 • 14 回帖 • 1 关注
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    17 引用 • 53 回帖 • 139 关注
  • 旅游

    希望你我能在旅途中找到人生的下一站。

    93 引用 • 899 回帖 • 1 关注
  • HTML

    HTML5 是 HTML 下一个的主要修订版本,现在仍处于发展阶段。广义论及 HTML5 时,实际指的是包括 HTML、CSS 和 JavaScript 在内的一套技术组合。

    107 引用 • 295 回帖
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 1 关注
  • 书籍

    宋真宗赵恒曾经说过:“书中自有黄金屋,书中自有颜如玉。”

    78 引用 • 391 回帖
  • Gitea

    Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。

    4 引用 • 16 回帖
  • 脑图

    脑图又叫思维导图,是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。

    30 引用 • 96 回帖 • 1 关注
  • 京东

    京东是中国最大的自营式电商企业,2015 年第一季度在中国自营式 B2C 电商市场的占有率为 56.3%。2014 年 5 月,京东在美国纳斯达克证券交易所正式挂牌上市(股票代码:JD),是中国第一个成功赴美上市的大型综合型电商平台,与腾讯、百度等中国互联网巨头共同跻身全球前十大互联网公司排行榜。

    14 引用 • 102 回帖 • 354 关注
  • Bootstrap

    Bootstrap 是 Twitter 推出的一个用于前端开发的开源工具包。它由 Twitter 的设计师 Mark Otto 和 Jacob Thornton 合作开发,是一个 CSS / HTML 框架。

    18 引用 • 33 回帖 • 667 关注
  • DevOps

    DevOps(Development 和 Operations 的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。

    51 引用 • 25 回帖
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖 • 44 关注
  • 博客

    记录并分享人生的经历。

    273 引用 • 2388 回帖
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    179 引用 • 407 回帖 • 491 关注