10 мая 2020

Редиректы NGINX для адресов с параметрами через MAP

Алексей Доронин
Руководитель, разработчик, дизайнер

Предположим, нам нужно сделать редиректы NGINX по такой схеме:

example.com/tags?tag=cool => example.com/something 

Исходный адрес с параметрами нужно перенаправлять на новый адрес. Название и значение параметра в новом адресе не используется.

Обычный редирект для такой задачи не будет работать.

## Так нельзя сделать

location = /tags?tag=cool {
  return 301 https://example.com/something;
}

Вариант решения — использовать директиву MAP.

MAP

Перед всеми объявлениями server, в самом начале конфигурационного файла пишем «таблицу» меппинга:

map $arg_tag $tag_new_destination {
    'cool'    /something;
    '6.0.1'    /tags/601;
    'alfa'    /newone;
}

В это примере переадресация будет:
example.com/tags?tag=cool => example.com/something
example.com/tags?tag=6.0.1 => example.com/tags/601
example.com/tags?tag=alfa => example.com/newone

Переменная $arg_tag — это переменная nginx, она создаётся по паттерну $arg_* из аргументов запроса. Тут у нас параметр ?tag, поэтому переменная называется $arg_tag.

$tag_new_destination — наша кастомная переменная.

Если таблица большая, nginx просит увеличить размер map_hash_bucket_size. Это меняется в nginx.conf. Например, для 100 адресов, где длинные русские транcлитерации хватило значения в 256.

map_hash_bucket_size 256;

Location

В нужной секции server пишем:

location /tags {
    error_page 420 = @tags_redirects;
 
    if ( $args ~ "tag=" ) { return 420; }
    try_files $uri $uri/ /index.php?$query_string;
}
 
location @tags_redirects {
    if ($tag_new_destination) {
      return 301 $tag_new_destination;
    }
}

Объявляем нужный нам location, в данном случае /tags. Мы хотим, чтобы редиректы обрабатывались только по этим адресам. В нём условие на наличие строки с параметрам tag  ( $args ~ "tag=" ). Если это условие не срабатывает (т.е. адрес /tags — без параметров и редирект не нужен), то пробрасываем на try_files (или иное стандартное решение). 

Если сработают параметры, то объявлен свой location @tags_redirects, где проверяется меппинг. $tag_new_destination — это просто переменная, которая ровна 1, если она есть в таблице меппинга.

Если адресов для переадресации много, их можно вынести в отдельный файл.

В начале конфигурационного файла пишем include для файла, где будет список с редиректами:

map $arg_tag $tag_new_destination {
  include includes/tags-redirects.conf;
}

В файле includes/tags-redirects.conf  перечислены все соответствия старых и новых адресов, для нашего примера, его содержание будет:

'cool'  /something;
'6.0.1' /tags/601;
'alfa'  /newone;