<!-- review: finished -->

<a id="http-rewrite"></a>

# Rewrite

该模块用于使用 PCRE 正则表达式更改请求 URI,返回重定向,以及有条件地选择配置。

[break](#break)、[if](#if)、[return](#return)、[rewrite](#id5) 和 [set](#set) 指令按以下顺序处理:

* 在 server 级别指定的该模块指令按顺序执行;
* 重复执行:
  > * 根据请求 URI 搜索 location;
  > * 在找到的 location 内指定的该模块指令按顺序执行;
  > * 如果请求 URI 被 [重写](#id5),则重复循环,但 [不超过](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#internal) 10 次。

<a id="directives-39"></a>

## 指令

<a id="index-0"></a>

<a id="break"></a>

### break

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `break`;           |
|--------------------------------------------------------------------------------------|--------------------|
| 默认值                                                                                  | —                  |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | server、location、if |

停止处理当前的 http_rewrite 模块指令集。

如果指令在 location 内指定,则请求的进一步处理将在此 location 中继续。

示例:

```nginx
if ($slow) {
    limit_rate 10k;
    break;
}
```

<a id="index-1"></a>

<a id="if"></a>

### if

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `if` (condition) { ... }   |
|--------------------------------------------------------------------------------------|----------------------------|
| 默认值                                                                                  | —                          |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | server、location            |

对指定的条件进行求值。如果为真,则执行大括号内指定的该模块指令,并将 if 指令内的配置分配给请求。if 指令内的配置从上一级配置继承。

#### WARNING
虽然可以在 if 块内使用其他模块的指令,
但不建议这样做,
因为这可能导致意外行为。

条件可以是以下任意一种:

* 变量名;如果变量的值为空字符串或 "0",则为假;
* 使用 "=" 和 "!=" 运算符将变量与字符串进行比较;
* 使用 "~"(区分大小写匹配)和 "~\*"(不区分大小写匹配)运算符将变量与正则表达式进行匹配。正则表达式可以包含捕获,这些捕获可在 $1..$9 变量中供后续重用。还可以使用否定运算符 "!~" 和 "!~\*"。如果正则表达式包含 "}" 或 ";" 字符,则整个表达式应该用单引号或双引号括起来。
* 使用 "-f" 和 "!-f" 运算符检查文件是否存在;
* 使用 "-d" 和 "!-d" 运算符检查目录是否存在;
* 使用 "-e" 和 "!-e" 运算符检查文件、目录或符号链接是否存在;
* 使用 "-x" 和 "!-x" 运算符检查可执行文件。

示例:

```nginx
if ($http_user_agent ~ MSIE) {
    rewrite ^(.*)$ /msie/$1 break;
}

if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
    set $id $1;
}

if ($request_method = POST) {
    return 405;
}

if ($slow) {
    limit_rate 10k;
}

if ($invalid_referer) {
    return 403;
}
```

#### NOTE
[$invalid_referer](https://cn.angie.software//angie/docs/configuration/modules/http/http_referer.md#v-invalid-referer) 内置变量的值由 [valid_referers](https://cn.angie.software//angie/docs/configuration/modules/http/http_referer.md#valid-referers) 指令设置。

<a id="index-2"></a>

<a id="return"></a>

### return

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `return` code [text];<br/><br/>`return` code URL;<br/><br/>`return` URL;   |
|--------------------------------------------------------------------------------------|----------------------------------------------------------------------------|
| 默认值                                                                                  | —                                                                          |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | server、location、if                                                         |

停止处理并向客户端返回指定的 `code`。非标准代码 444 会在不发送响应头的情况下关闭连接。

可以指定重定向 URL(用于代码 301、302、303、307 和 308)或响应正文文本(用于其他代码)。响应正文文本和重定向 URL 可以包含变量。作为特殊情况,重定向 URL 可以指定为此服务器的本地 URI,在这种情况下,完整的重定向 URL 将根据请求方案($scheme)以及 [server_name_in_redirect](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#server-name-in-redirect) 和 [port_in_redirect](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#port-in-redirect) 指令形成。

此外,代码为 302 的临时重定向 URL 可以指定为唯一参数。此类参数应以 `http://`、`https://` 或 "$scheme" 字符串开头。URL 可以包含变量。

另请参阅 [error_page](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#error-page) 指令。

<a id="index-3"></a>

<a id="id5"></a>

### rewrite

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `rewrite` regex replacement [flag];   |
|--------------------------------------------------------------------------------------|---------------------------------------|
| 默认值                                                                                  | —                                     |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | server、location、if                    |

如果指定的正则表达式与请求 URI 匹配,则 URI 将按 `replacement` 字符串中指定的方式更改。rewrite 指令按其在配置文件中出现的顺序依次执行。可以使用 `flags` 终止指令的进一步处理。如果 `replacement` 字符串以 `http://`、`https://` 或 "$scheme" 开头,则处理停止并将重定向返回给客户端。

可选的 `flag` 参数可以是以下之一:

| `last`      | 停止处理当前的 http_rewrite 模块指令集,并开始搜索与更改后的 URI 匹配的新 location;                       |
|-------------|--------------------------------------------------------------------------------|
| `break`     | 停止处理当前的 http_rewrite 模块指令集,与 break 指令相同;                                       |
| `redirect`  | 返回代码为 302 的临时重定向;当 `replacement` 字符串不以 `http://`、`https://` 或 "$scheme" 开头时使用; |
| `permanent` | 返回代码为 301 的永久重定向。                                                              |

完整的重定向 URL 根据请求方案($scheme)以及 [server_name_in_redirect](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#server-name-in-redirect) 和 [port_in_redirect](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#port-in-redirect) 指令形成。

示例:

```nginx
server {
#    ...
    rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
    rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra  last;
    return  403;
#    ...
}
```

但如果这些指令放在 "/download/" location 内,则应将 `last` 标志替换为 `break`,否则 Angie 将进行 10 次循环并返回 500 错误:

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

如果 `replacement` 字符串包含新的请求参数,则先前的请求参数将附加在它们之后。如果不希望这样,在替换字符串末尾放置一个问号可以避免附加它们,例如:

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

如果正则表达式包含 "}" 或 ";" 字符,则整个表达式应该用单引号或双引号括起来。

<a id="index-4"></a>

<a id="rewrite-log"></a>

### rewrite_log

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `rewrite_log` `on` | `off`;   |
|--------------------------------------------------------------------------------------|-------------------------------|
| 默认值                                                                                  | `rewrite_log off;`            |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | http、server、location、if       |

启用或禁用将 http_rewrite 模块指令处理结果以 notice 级别记录到 [error_log](https://cn.angie.software//angie/docs/configuration/modules/core.md#error-log) 中。

<a id="index-5"></a>

<a id="set"></a>

### set

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `set` $variable value;   |
|--------------------------------------------------------------------------------------|--------------------------|
| 默认值                                                                                  | —                        |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | server、location、if       |

为指定的变量设置值。该值可以包含文本、变量及其组合。

<a id="index-6"></a>

<a id="uninitialized-variable-warn"></a>

### uninitialized_variable_warn

| [语法](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)   | `uninitialized_variable_warn` `on` | `off`;   |
|--------------------------------------------------------------------------------------|-----------------------------------------------|
| 默认值                                                                                  | `uninitialized_variable_warn on;`             |
| [上下文](https://cn.angie.software//angie/docs/configuration/configfile.md#configfile)  | http、server、location、if                       |

控制是否记录有关未初始化变量的警告。

<a id="internal-implementation"></a>

## 内部实现

http_rewrite 模块指令在配置阶段被编译为内部指令,这些指令在请求处理期间被解释执行。解释器是一个简单的虚拟栈机器。

例如,指令

```nginx
location /download/ {
    if ($forbidden) {
        return 403;
    }

    if ($slow) {
        limit_rate 10k;
    }

    rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;
}
```

将被转换为这些指令:

```console
variable $forbidden
check for zero
    return 403
    end of code
variable $slow
check for zero
match of regular expression
copy "/"
copy $1
copy "/mp3/"
copy $2
copy ".mp3"
end of regular expression
end of code
```

请注意,没有 [limit_rate](https://cn.angie.software//angie/docs/configuration/modules/http/index.md#limit-rate) 指令的指令,因为它与 `http_rewrite` 模块无关。为 `if` 块创建了单独的配置。如果条件为真,请求将获得此配置,其中 `limit_rate` 等于 10k。

指令

```nginx
rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;
```

如果将正则表达式中的第一个斜杠移到括号内,可以减少一条指令:

```nginx
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;
```

相应的指令将如下所示:

```console
match of regular expression
copy $1
copy "/mp3/"
copy $2
copy ".mp3"
end of regular expression
end of code
```
