1、rewirte模块(ngx_http_rewrite_module)

1.1 介绍

该模块允许使用正则表达式改变URI,并且根据变量来跳转以及选择配置。rewirte的循环最多会执行10次,然后Nginx会返回一个500错误。

1.2 常用正则

  1. . : 匹配除换行符以外的任意字符
  2. ? : 重复0次或1次
  3. + : 重复1次或更多次
  4. * : 重复0次或更多次
  5. \d :匹配数字
  6. ^ : 匹配字符串的开始
  7. $ : 匹配字符串的介绍
  8. {n} : 重复n次
  9. {n,} : 重复n次或更多次
  10. [c] : 匹配单个字符c
  11. [a-z] : 匹配a-z小写字母的任意一个

1.3 全局变量

下面是可以用作if判断的全局变量:

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

示例:http://localhost:88/test1/test2/test.php这个URL,

  1. $host:localhost
  2. $server_port:88
  3. $request_uri:http://localhost:88/test1/test2/test.php
  4. $document_uri:/test1/test2/test.php
  5. $document_root:/var/www/html
  6. $request_filename:/var/www/html/test1/test2/test.php

2、rewirte常用模块指令

2.1 break

  • 语法:break
  • 默认值:none
  • 作用域:server,location,if
  • 作用:此指令的意思是停止执行当前虚拟主机的后续rewrite指令集
  • 示例:限速,$slow可以通过 set 指令设置
    1. if ($slow) {
    2. limit_rate 10k;
    3. break;
    4. }

2.2 if

  • 语法:if (condition) { … }
  • 默认值:none
  • 作用域:server,location
  • 作用:对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行。
  • if条件(conditon)可以是如下任何内容: ```html
  1. 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false;
  2. 使用“=”和“!=”比较一个变量和字符串;
  3. 使用“~”做正则表达式匹配,“~”做不区分大小写的正则匹配,“!~”做区分大小写的正则不匹配;!~做不区分大小写的正则不匹配;
  4. 使用“-f”和“!-f” 检查一个文件是否存在;
  5. 使用“-d”和“!-d”检查一个目录是否存在;
  6. 使用“-e”和“!-e”检查一个文件、目录、符号链接是否存在;
  7. 使用“-x”和“ !-x”检查一个文件是否可执行; ```

示例:

  1. # 如果UA包含"MSIE",rewrite请求到/msid/目录下
  2. if ($http_user_agent ~ MSIE) {
  3. rewrite ^(.*)$ /msie/$1 break;
  4. }
  5. # 如果cookie匹配正则,设置变量$id等于正则引用部分
  6. if ($http_cookie ~* "id=([^;] +)(?:;|$)" ) {
  7. set $id $1;
  8. }
  9. # 如果提交方法为POST,则返回状态405(Method not allowed)。return不能返回301,302
  10. if ($request_method = POST ) {
  11. return 405;
  12. }
  13. # 如果请求的文件名不存在,则反向代理到localhost 。这里的break也是停止rewrite检查
  14. if (!-f $request_filename) {
  15. break;
  16. proxy_pass http://127.0.0.1;
  17. }
  18. # 限速,$slow可以通过 set 指令设置
  19. if ($slow) {
  20. limit_rate 10k;
  21. }
  22. # 给某个访问IP返回403
  23. if ( $remote_addr = "202\.38\.78\.85" ){
  24. return 403;
  25. }
  26. # 防盗链
  27. location ~* \.(gif|jpg|png|swf|flv)$ {
  28. valid_referers none blocked www.baidu.com www.ywnds.com;
  29. if ($invalid_referer) {
  30. return 404;
  31. }
  32. }

2.3 return

  • 语法:return code
  • 默认值:none
  • 作用域:server, location, if
  • 作用:这个指令根据规则的执行情况,返回一个状态值给客户端。可使用值包括:204,400,402-406,408,410,411,413,416以及500-504。也可以发送非标准的444代码-未发送任何头信息下结束连接。

    2.4 rewrite

  • 语法:rewrite regex replacement [flag];

  • 默认值:none
  • 作用域:server, location, if
  • 作用:rewrite指令的功能就是,使用nginx提供的全局变量或自己设置的变量,然后结合正则表达式和标志位实现url重写以及重定向。指令根据配置文件中的顺序来执行。只对域名后边的除去传递的参数外的字符串起作用,例如 http://ywnds.com/a/we/index.php?id=1&u=str,只对/a/we/index.php重写。
  • 如果想对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用proxy_pass反向代理。

示例:

  1. # www.mydomain.com/foo 跳转到 mydomain.com/foo
  2. if ($host ~* www\.(.*)) {
  3. set $host_without_www $1;
  4. rewrite ^(.*)$ http://$host_without_www$1 permanent; # $1代表括号里的内容
  5. }

2.5 set

  • 语法:set variable value
  • 默认值:none
  • 作用域:server, location, if
  • 作用:定义一个变量并赋值,值可以是文本,变量或者文本变量混合体

    3.flag标识位

    3.1 标识位种类

  • last,完成该rewrite规则的执行后,停止处理后续rewrite指令集,然后查找匹配改变后URI的新location;

  • break,完成该rewrite规则的执行后,停止处理后续rewrite指令集,并不再重新查找;但是当前location内剩余非rewrite语句和location外的的非rewrite语句可以执行;
  • redirect,返回302临时重定向,地址栏会显示跳转后的地址;
  • permanent,返回301永久重定向,地址栏会显示跳转后的地址;即表示如果客户端不清理浏览器缓存,那么返回的结果将永久保存在客户端浏览器中了。

    3.2 last和break区别

    因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return指令无法返回301,302的原因了。这里last和break区别有点难以理解:

  • last一般写在server和if中,而break一般使用在location中;

  • last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配;
  • break和last都能阻止继续执行后面的rewrite指令。

4、示例

4.1 示例1:last和break区别

/download/api/media/test.txt 跳转到/download/api/mp3/test.mp3

  1. server {
  2. ...
  3. rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
  4. rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last;
  5. return 403;
  6. ...
  7. }

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

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

4.2 示例2:去除原请求中的请求参数

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

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

4.3 示例3: 正则内带特殊符号{}

对花括号“}”或“;”来说,使用时需要用双引号或单引号包围。因为他们既能用在重定向的正则表达式里,也是用在配置文件里分割代码块, 为了避免冲突, 正则表达式里带花括号的话,应该用双引号(或者单引号)包围。比如,要将类似以下的URI:”/photos/123456″重定向到”/path/to/photos/12/1234/123456.png”可以用以下方法 (注意双引号):

  1. rewrite "/photos/([0-9] {2})([0-9] {2})([0-9] {2})" /path/to/photos/$1/$1$2/$1$2$3.png;

4.4 示例4:http跳转到https

访问www.a.com跳转到https://www.a.com

  1. rewrite (.*) https://www.a.com/$1 permanent

还可以这样写:

  1. server {
  2. listen 80;
  3. server_name www.a.com;
  4. return 301 https://$server_name$request_uri;
  5. }

4.5 示例5:将uri某部分作为参数传给后端

www.a.com/todo/34跳转为www.a.com/todo?id=34

  1. rewrite ^/todos/(.*) /todos?id=$1 break;

4.6 其他使用场景待补充