Nginx 中 rewrite 配置详解

原文地址

前言

nginx 通过 ngx_http_rewrite_module 模块支持 URI 重写、支持 if 条件判断,但不支持 else。

rewrite 只能放在 server { }location { }if { } 中,并且只能对域名后边的除去传递的参数外的字符串起作用,例如http://aaa.com/a/we/index.php?id=1&u=str只对/a/we/index.php重写。语法为 rewrite regex replacement [flag];

指令执行顺序

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

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

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

指令详解

if 指令

语法:if(condition) {…}
作用域:serverlocation
功能:该指令用来支持条件判断,并根据条件判断结果选择不同的 Nginx 配置。
if 中的几种判断条件

  • 一个变量名;false 如果这个变量是空字符串或者以0开始的字符串;
  • 使用 =!= 比较的一个变量和字符串
  • 是用 ~~* 与正则表达式匹配的变量,如果这个正则表达式中包含},;则整个表达式需要用” 或’ 包围
  • 使用 -f!-f 检查一个文件是否存在
  • 使用 -d!-d 检查一个目录是否存在
  • 使用 -e!-e检查一个文件、目录、符号链接是否存在
  • 使用 -x!-x 检查一个文件是否可执行

示例:

set $variable "0"; 
if ($variable) {
    # 不会执行,因为 "0" 为 false
    break;            
}

# 使用变量与正则表达式匹配 没有问题
if ( $http_host ~ "^star\.igrow\.cn$" ) {
    break;            
}

# 字符串与正则表达式匹配 报错
if ( "star" ~ "^star\.igrow\.cn$" ) {
    break;            
}
# 检查文件类的 字符串与变量均可
if ( !-f "/data.log" ) {
    break;            
}

if ( !-f $filename ) {
    break;            
}

return 指令

语法:
return code [text];
return code URL;
return URL;
作用域:serverlocationif
功能:停止处理并将指定的 code 码返回给客户端。 非标准 code 码 444 关闭连接而不发送响应报头。

该指令用于检查一个条件是否符合,如果条件符合,则执行大括号内的语句。If 指令不支持嵌套,不支持多个条件 && 和 || 处理。

从0.8.42版本开始, return 语句可以指定重定向 URI (状态码可以为如下几种 301,302,303,307),

也可以为其他状态码指定响应的文本内容,并且重定向的 URI 和响应的文本可以包含变量。

有一种特殊情况,就是重定向的url可以指定为此服务器本地的 URI,这样的话,nginx 会依据请求的协议 $schemeserver_name_in_redirectport_in_redirect 自动生成完整的 URI。

示例:如果访问的 URI 以 .sh.bash 结尾,则返回 403 状态码

location ~ .*\.(sh|bash)?$
{
   return 403;
}

rewrite 指令

语法:rewrite regex replacement [flag];
作用域:serverlocationif
功能:如果一个URI匹配指定的正则表达式regex,URI就按照 replacement 重写。

rewrite 按配置文件中出现的顺序执行。可以使用 flag 标志来终止指令的进一步处理。

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

示例:第一种情况,重写的字符串带 http://

location ^~ /redirect {
    # 当匹配前缀表达式 /redirect/(.*)时 请求将被临时重定向到 http://www.$1.com
    # 相当于 flag 写为 redirect
    rewrite ^/(.*)$ http://www.$1.com;
    return 200 "ok";
}

在浏览器中输入 127.0.0.1:8080/redirect/baidu ,则临时重定向到 www.baidu.com 后面的 return 指令将没有机会执行了。

location ^~ /redirect {
    rewrite ^/(.*)$ www.$1.com;
    return 200 "ok";
}
# 发送请求如下
# curl 127.0.0.1:8080/redirect/baidu
# ok

此处没有带 http:// 所以只是简单的重写。请求的 URI 由 /test1/baidu 重写为 www.baidu.com 因为会顺序执行 rewrite 指令,所以 下一步执行 return 指令,响应后返回 ok

flag 有四种参数可以选择:

  1. last 停止处理后续 rewrite 指令集,然后对当前重写的新 URI 在 rewrite 指令集上重新查找。
  2. break 停止处理后续 rewrite 指令集,并不再重新查找,但是当前location 内剩余非 rewrite 语句和 location 外的 非rewrite 语句可以执行。
  3. redirect 如果 replacement 不是以 http://https:// 开始,返回 302 临时重定向
  4. permanent 返回 301 永久重定向

示例 1:

# rewrite 后面没有任何 flag 时就顺序执行 
# 当 location 中没有 rewrite 模块指令可被执行时 就重写发起新一轮location 匹配
location / {
    # 顺序执行如下两条rewrite指令 
    rewrite ^/test1 /test2;
    rewrite ^/test2 /test3;  # 此处发起新一轮 location 匹配 URI为/test3
}

location = /test2 {
    return 200 “/test2”;
}  

location = /test3 {
    return 200 “/test3”;
}
# 发送如下请求
# curl 127.0.0.1:8080/test1
# /test3

如果正则表达regex式中包含 “}” 或 “;”,那么整个表达式需要用双引号或单引号包围。

示例 2:

location / {
    rewrite ^/test1 /test2;
    rewrite ^/test2 /test3 last;  # 此处发起新一轮location匹配 uri为/test3
    rewrite ^/test3 /test4;
    proxy_pass http://www.baidu.com;
}

location = /test2 {
    return 200 "/test2";
}  

location = /test3 {
    return 200 "/test3";
}
location = /test4 {
    return 200 "/test4";
}

发送如下请求 curl 127.0.0.1:8080/test1 返回 /test3

当如果将上面的 location / 改成如下代码

location / {
    rewrite ^/test1 /test2;
    # 此处不会发起新一轮location匹配;当是会终止执行后续rewrite模块指令重写后的 URI 为 /more/index.html
    rewrite ^/test2 /more/index.html break;  
    rewrite /more/index\.html /test4; # 这条指令会被忽略

    # 因为 proxy_pass 不是rewrite模块的指令 所以它不会被 break终止
    proxy_pass https://www.baidu.com;
}

发送请求 127.0.0.1:8080/test1
代理到 https://www.baidu.com

rewrite 后的请求参数:
如果替换字符串 replacement 包含新的请求参数,则在它们之后附加先前的请求参数。如果你不想要之前的参数,则在替换字符串 replacement 的末尾放置一个问号,避免附加它们。

# 由于最后加了个 ?,原来的请求参数将不会被追加到 rewrite 之后的 URI 后面*
rewrite ^/users/(.*)$ /show?user=$1? last;

rewrite_log 指令

语法:rewrite_log on | off;
默认值:rewrite_log off;
作用域:httpserverlocationif
功能:开启或关闭以 notice 级别打印 rewrite 处理日志到 error log 文件。

set 指令

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

uninitialized_variable_warn 指令

作用域:httpserverlocationif
语法:uninitialized_variable_warn on | off;
默认值:uninitialized_variable_warn on
功能:控制是否记录 有关未初始化变量的警告。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值