<!-- review: finished -->

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

# Rewrite

Позволяет изменять URI запроса с помощью регулярных выражений PCRE, делать перенаправления и выбирать конфигурацию по условию.

Директивы [break](#break), [if](#if), [return](#return), [rewrite](#id5) и [set](#set) обрабатываются в следующем порядке:

* последовательно выполняются директивы этого модуля, описанные на уровне `server`;
* в цикле:
  > * ищется `location` по URI запроса;
  > * последовательно выполняются директивы этого модуля, описанные в найденном `location`;
  > * цикл повторяется, если URI запроса [изменялся](#id5), но [не более](https://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://angie.software//angie/docs/configuration/configfile.md#configfile)   | `break`;             |
|------------------------------------------------------------------------------------------|----------------------|
| По умолчанию                                                                             | —                    |
| [Контекст](https://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://angie.software//angie/docs/configuration/configfile.md#configfile)   | `if` (условие) { ... }   |
|------------------------------------------------------------------------------------------|--------------------------|
| По умолчанию                                                                             | —                        |
| [Контекст](https://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://angie.software//angie/docs/configuration/modules/http/http_referer.md#v-invalid-referer) задается директивой [valid_referers](https://angie.software//angie/docs/configuration/modules/http/http_referer.md#valid-referers).

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

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

### return

| [Синтаксис](https://angie.software//angie/docs/configuration/configfile.md#configfile)   | `return` код [текст];<br/><br/>`return` код URL;<br/><br/>`return` URL;   |
|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------|
| По умолчанию                                                                             | —                                                                         |
| [Контекст](https://angie.software//angie/docs/configuration/configfile.md#configfile)    | server, location, if                                                      |

Завершает обработку и возвращает клиенту указанный `код`. Нестандартный
код 444 закрывает соединение без передачи заголовка ответа.

Можно задать либо URL перенаправления (для кодов 301, 302, 303, 307 и 308) либо текст тела ответа (для остальных кодов). В тексте тела ответа и URL перенаправления можно использовать переменные. Как частный случай, URL перенаправления может быть задан как URI, локальный для данного сервера, при этом полный URL перенаправления формируется согласно схеме запроса ($scheme) и директивам [server_name_in_redirect](https://angie.software//angie/docs/configuration/modules/http/index.md#server-name-in-redirect) и [port_in_redirect](https://angie.software//angie/docs/configuration/modules/http/index.md#port-in-redirect).

Кроме того, в качестве единственного параметра можно указать URL для временного перенаправления с кодом 302. Такой параметр должен начинаться со строк `http://`, `https://` или "$scheme". В URL можно использовать переменные.

См. также директиву [error_page](https://angie.software//angie/docs/configuration/modules/http/index.md#error-page).

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

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

### rewrite

| [Синтаксис](https://angie.software//angie/docs/configuration/configfile.md#configfile)   | `rewrite` regex замена [флаг];   |
|------------------------------------------------------------------------------------------|----------------------------------|
| По умолчанию                                                                             | —                                |
| [Контекст](https://angie.software//angie/docs/configuration/configfile.md#configfile)    | server, location, if             |

Если указанное регулярное выражение regex соответствует URI запроса, URI
изменяется в соответствии со строкой замены. Директивы `rewrite`
выполняются последовательно, в порядке их следования в конфигурационном файле. С
помощью флага можно прекратить дальнейшую обработку директив. Если строка
замены начинается с `http://`, `https://` или `$scheme`, то
обработка завершается и клиенту возвращается перенаправление.

Необязательный параметр флаг может быть задан одним из следующих значений:

| `last`      | завершает обработку текущего набора директив модуля `http_rewrite`, после чего ищется новый `location`, соответствующий измененному URI;          |
|-------------|---------------------------------------------------------------------------------------------------------------------------------------------------|
| `break`     | завершает обработку текущего набора директив модуля `http_rewrite` аналогично директиве `break`;                                                  |
| `redirect`  | возвращает временное перенаправление с кодом 302; используется, если<br/>строка `замены` не начинается с `http://`, `https://` или<br/>"$scheme"; |
| `permanent` | возвращает постоянное перенаправление с кодом 301.                                                                                                |

Полный URL перенаправлений формируется согласно схеме запроса ($scheme) и директив [server_name_in_redirect](https://angie.software//angie/docs/configuration/modules/http/index.md#server-name-in-redirect) и [port_in_redirect](https://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;
#    ...
}
```

Если же эти директивы поместить в location "/download/", то нужно заменить флаг `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;
}
```

Если в строке `замены` указаны новые аргументы запроса, то предыдущие
аргументы запроса добавляются после них. Если такое поведение нежелательно,
можно отказаться от этого добавления, указав в конце строки замены знак вопроса,
например:

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

Если в регулярном выражении встречаются символы "}" или ";", то все выражение следует заключить в одинарные или двойные кавычки.

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

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

### rewrite_log

| [Синтаксис](https://angie.software//angie/docs/configuration/configfile.md#configfile)   | `rewrite_log` `on` | `off`;   |
|------------------------------------------------------------------------------------------|-------------------------------|
| По умолчанию                                                                             | `rewrite_log off;`            |
| [Контекст](https://angie.software//angie/docs/configuration/configfile.md#configfile)    | http, server, location, if    |

Разрешает или запрещает записывать в [error_log](https://angie.software//angie/docs/configuration/modules/core.md#error-log) на уровне `notice` результаты обработки директив модуля `http_rewrite`.

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

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

### set

| [Синтаксис](https://angie.software//angie/docs/configuration/configfile.md#configfile)   | `set` $переменная значение;   |
|------------------------------------------------------------------------------------------|-------------------------------|
| По умолчанию                                                                             | —                             |
| [Контекст](https://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://angie.software//angie/docs/configuration/configfile.md#configfile)   | `uninitialized_variable_warn` `on` | `off`;   |
|------------------------------------------------------------------------------------------|-----------------------------------------------|
| По умолчанию                                                                             | `uninitialized_variable_warn on;`             |
| [Контекст](https://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
переменная $forbidden
проверка на ноль
    возврат 403
    завершение всего кода
переменная $slow
проверка на ноль
проверка регулярного выражения
копирование "/"
копирование $1
копирование "/mp3/"
копирование $2
копирование ".mp3"
завершение регулярного выражения
завершение всего кода
```

Обратите внимание, что инструкций для директивы [limit_rate](https://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
проверка регулярного выражения
копирование $1
копирование "/mp3/"
копирование $2
копирование ".mp3"
завершение регулярного выражения
завершение всего кода
```
