A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

  重定向
  网站在使用 Nginx 时都会进行个性化配置满足自己的业务需要,而 URL 重写几乎是每个网站都必做的事情,Nginx 的 URL 重写规则不像 Apache 那样简单直接,逻辑相对要复杂一些,本文将通过例子的方式帮助大家理解 Nginx rewrite 原理,希望能对您有些启发。
  Nginx 中重定向有多种方式:
  外部重定向
  return 指令返回 301 或 302(return 也可以返回其他状态码),可以放在 server 或 location 块中。例如:
  还可以使用 rewrite 指令,例如:
  内部重定向
  return + error_page 指令的组合,或 try_files 指令和 rewrite 指令,非常灵活。
  本文主要讲解 rewrite 的工作原理,其他指令的使用方法大家可以自行查阅 Nginx 官网。在使用 Nginx 的 rewrite 指令时,flag 可以设置为 last 和 break,这两个 flag 很容易混淆,后面我们会比较这两个 flag 的区别,下面通过示例我们来认识一下 rewrite 指令。
  rewrite 语法
  regex: 对请求的 URI 做正则匹配
  replacement:目标 uri 匹配成功后替换的 url
  可以使用的 flag 有以下 4 个(flag 也可以为空):
  redirect:返回 302 临时重定向,客户端地址栏会显示跳转后的地址;
  permanent:返回 301 永久重定向,客户端地址栏会显示跳转后的地址;
  last:内部重定向,停止处理后续 rewrite 模块中的指令(客户端无感知);
  break:内部重定向,停止处理后续 rewrite 模块中的指令(客户端无感知)。
  NOTE:
  1. regex 匹配的是 uri,不包含 hostname 和 query string,默认 query string 是被追加到 replacement 末尾,如果不希望在末尾追加请求的 query string,可以在 replacement 的末尾加一个 "?"。
  2. 如果 replacement 是以 "http://","https://" 或 $scheme" 开始的字符串,那么 rewrite 指令停止后面的处理,直接返回给客户端,没有指定 flag 时,与 redirect 效果相同。
  3. 没有 flag 的 rewrite 指令根据出现的顺序执行,flag 可以控制指令的执行顺序。
  4. 在配置中开启 rewrite_log 指令,日志文件中会记录 rewrite 的匹配过程,有助于调试 rewrite 问题。
  Nginx 请求处理流程
  在讲 rewrite 前我们先来简单了解下 Nginx 请求处理流程,为什么需要了解请求处理流程呢?因为 rewrite 操作与其中几个 phase 关系很密切,熟悉了请求处理流程,理解 rewrite 执行逻辑就会很容易。在 Nginx 内部将请求处理划分为 11 个 phase,每个 phase 会执行对应的 handler,这里我们不打算逐个进行讲解。在 11 个 phase 中与 rewrite 指令逻辑有关的只有 4 个,所以在本文我们主要关注 SERVER_REWRITE、FIND_CONFIG、REWRITE 和 POST_REWRITE 这四个 phase。
  首先我们要清楚的是:
  server 块中的 rewrite 模块指令在 SERVER_REWRITE 阶段解析;
  location 块中的 rewrite 模块指令在 REWRITE 阶段解析;
  SERVER_REWRITE - 请求到达后首先处理这个阶段的 rewrite 指令操作
  FIND_CONFIG - 根据 SERVER_REWRITE 阶段得到的 uri 查找 location
  REWRITE - 确定 location 后执行 locaton 中 rewrite 操作
  POST_REWRITE - 根据上一阶段的 uri 重写结果做决策,可能跳回 FIND_CONFIG 阶段重新查找 location,也可能继续执行后边的 phase。例如:在 location 中配置了 rewrite 指令并且指定 flag=break,执行完本条 rewrite 终止后边的 rewrite 匹配,然后执行 PREACCESS 阶段中的 handler。同样的场景下 flag=last,执行完本条 rewrite 终止后边的 rewrite 匹配,然后跳到 FIND_CONFIG 阶段再次查找 location。未指定 flag 的情况与 flag=last 类似,唯一区别是在同一层级中未指定 flag 的 rewrite 语句不会终止后续的 rewrite 匹配。
  通过例子理解 rewrite 指令
  1
  未指定 flag
  未指定 flag 的 rewrite 会按照出现顺序进行匹配,server 块中 rewrite 匹配完以后根据改写的 uri 查找 location,然后再匹配 location 中的 rewrite,location 中的 rewrite 指令匹配成功后会再次查找 location。
  说明:
  匹配第一条 rewrite 成功,uri 被改写为 / mi_one/mi_zero/hello,没有指定 flag 的 rewrite 继续匹配后面的 rewrite
  匹配第二条 rewrite 成功,此时 uri 被改写为 / mi_two/mi_zero/hello
  查找 location,mi_two 被确定为最终的 location
  说明:
  匹配 server 块中的 rewrite 成功,uri 被改写为 / mi_one/hello
  server 块中只有一条 rewrite 指令,开始查找 location
  location mi_one 被找到,开始匹配 location 中 rewrite
  location 中的 rewrite 匹配成功,uri 被改写为 / mi_two/hello
  再次查找 location,mi_two 被确定为最终使用的 location
  再来看一个例子:
  说明:
  匹配第一条 rewrite 成功,由于 replacement 是以 http:// 开始的字符串,所以 rewrite 指令直接返回给客户端 302,并且停止匹配后续的 rewrite。
  2
  flag 指定为 redirect
  指定 flag 为 redirect 时,rewrite 匹配成功后直接返回给客户端 302,不会继续匹配后续的 rewrite。
  再来看一个例子:
  3
  flag 指定为 permanent
  指定 flag=permanent 时,与 redirect 效果相同,唯一的区别 http code 返回 301。
  4
  flag 指定为 last
  rewrite 的 last 和 break 这两个 flag 使用场景很多并且也很容易混淆,他们的共同点都会停止当前层级后续的 rewrite 匹配,区别需要分两种情况:第一种使用在 server block 中,last 和 break 没有区别。第二种使用在 location block 中,last 会根据改写的 uri 重新查找 location,break 不会重新查找 location,而是在当前 location 中执行后续的指令。(注:last 和 break 不仅停止 rewrite 的匹配,同时还会停止 Nginx rewrite 模块中其他指令的执行,例如:set、return 指令)
  说明:
  匹配第一条 rewrite 成功,uri 被改写为 / mi_two/hello,由于 flag 指定为 last 会停止后续的 rewrite 的匹配(仅停止 server block 中的 rewrite 匹配),所以会根据改写的 uri 查找 location
  再来看一个 last 在 location block 中使用的例子:
  说明:
  匹配 server block 中第一条 rewrite 成功,uri 被改写为 / mi_one/hello
  查找 location,mi_one 被确定为使用的 location
  匹配 location block 中的 rewrite,location 中的第一条 rewrite 匹配成功,uri 被改写为 / mi_three/mi_one/hello,由于 flag 指定为 last,所以停止 location 中后续的 rewrite 匹配,此时再根据 uri=/mi_three/mi_one/hello 查找 location,最终 mi_three 被确定为使用的 location
  5
  flag 指定为 break
  说明:
  匹配 server block 中第一条 rewrite 成功,uri 被改写为 / mi_two/hello,由于 flag 指定为 break 所以会停止 server block 中后续的 rewrite 匹配,根据 uri=/mi_two/hello 查找 location,最终 mi_two 被确定为使用的 location
  说明:
  匹配 server block 中第一条 rewrite 成功,uri 被改写为 / mi_one/hello
  根据 uri=/mi_one/hello 查找 location,mi_one 被确定为使用的 location
  匹配 location block 中的 rewrite,location 中的第一条 rewrite 匹配成功,uri 被改写为 / mi_three/mi_one/hello,由于 flag 指定为 break,所以停止 location 中后续的 rewrite 匹配,并且把当前 location 作为最终使用的 location,不会重新查找 location(last 会继续查找 location)
  总结
  在 Nginx 的配置中可以实现简单的编程,理解起来相对有点难度,通过阅读此文希望能对你有些启发,能够根据项目需求可以配置更复杂的 rewrite 规则。想要更深入的理解 rewrite,还需要大家自己动手实践。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马