Faz muito tempo que não escrevo nada, então vamos diluir o final da sexta-feira com buscas simples, mas nem sempre óbvias, no Nginx .
Este servidor web tem uma diretiva de mapa maravilhosa que permite simplificar e encurtar as configurações. A essência da diretiva é que ela permite criar uma nova variável, cujo valor depende dos valores de uma ou mais das variáveis originais. A diretiva se torna ainda mais poderosa ao usar expressões regulares, mas ao mesmo tempo é esquecida sobre um ponto importante. Trecho do manual:
Como as variáveis são avaliadas apenas no momento do uso, mesmo um grande número de declarações de variáveis de mapa em si não incorre em nenhuma sobrecarga de processamento de consulta adicional.
E aqui é importante não só que “o mapa não acarreta custos adicionais para o processamento de pedidos”, mas também que “as variáveis são calculadas apenas no momento da utilização”.
Como você sabe, a configuração do Nginx é principalmente declarativa. Isso também se aplica à diretiva map e, apesar de estar localizada no contexto http , não é avaliada até que a solicitação seja processada. Ou seja, ao usar a variável resultante no servidor de contextos , localização, se , etc. nós "substituímos" não o resultado final do cálculo, mas apenas a "fórmula" pela qual esse resultado será calculado no momento certo. Não há problemas nesta casuística de configuração até usarmos expressões regulares. Nomeadamente expressões regulares com seleções. Mais precisamente, expressões regulares com seleções sem nome. É mais fácil mostrar com um exemplo.
Digamos que temos um domínio example.com com muitos subdomínios de terceiro nível , como ru.example.com, en.example.com, de.example.com , etc., e queremos redirecioná-los para novos subdomínios ru.example. org, en.example.org, de.example.org , etc. Em vez de descrever centenas de linhas de redirecionamentos, faremos o seguinte:
map $host $redirect_host {
default "example.org";
"~^(\S+)\.example\.com$" $1.example.org;
}
server {
listen *:80;
server_name .example.com;
location / {
rewrite ^(.*)$ https://$redirect_host$1 permanent;
}
Aqui, esperávamos erroneamente que, ao solicitar ru.example.com, a regex fosse calculada no mapa e, portanto, quando chegar à localização , a variável $ redirect_host conteria o valor de ru.example.org , mas na realidade isso não é o caso:
$ GET -Sd ru.example.com GET http://ru.example.com 301 Moved Permanently GET https://ru.example.orgru
, ru.example.orgru. - , " " rewrite .
- regexp map , , :
map $host $redirect_host {
default "example.org";
"~^(\S+)\.example\.com$" $1.example.org;
}
server {
listen *:80;
server_name .example.com;
location / {
return 301 https://$redirect_host$request_uri;
}
}
, ( ).
map:
map $host $redirect_host {
default "example.org";
"~^(?<domainlevel3>\S+)\.example\.com$" $domainlevel3.example.org;
}
server {
listen *:80;
server_name .example.com;
location / {
rewrite ^(.*)$ https://$redirect_host$1 permanent;
}
}
:
$ GET -Sd ru.example.com GET http://ru.example.com 301 Moved Permanently GET https://ru.example.orgru
já que nossa alocação sem nome $ 1 obterá o resultado de $ domainlevel3 nomeado . Ou seja, você precisa usar seleções nomeadas em ambos os regexes:
map $host $redirect_host {
default "example.org";
"~^(?<domainlevel3>\S+)\.example\.com$" $domainlevel3.example.org;
}
server {
listen *:80;
server_name .example.com;
location / {
rewrite ^(?<requri>.*)$ https://$redirect_host$requri permanent;
}
}
E agora tudo funciona conforme o esperado:
$ GET -Sd ru.example.com GET http://ru.example.com 301 Moved Permanently GET https://ru.example.org/