AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / server / Perguntas / 1168303
Accepted
Ivan Shatsky
Ivan Shatsky
Asked: 2024-11-29 19:18:42 +0800 CST2024-11-29 19:18:42 +0800 CST 2024-11-29 19:18:42 +0800 CST

Qual é o algoritmo real de seleção de localização do nginx?

  • 772

Tendo esta configuração nginx simples:

location / {
    return 200 "Location 1\n";
}
location ~ \.php$ {
    return 200 "Location 2\n";
}
location /tmp {
    return 200 "Location 3\n";
    location ~ \.php$ {
        return 200 "Location 3a\n";
    }
}

Por que as /tmp/foo.phpsolicitações fornecem a Location 3aresposta, embora, de acordo com a documentação , o local da regex Location 2deva ultrapassar a solicitação, a menos que o local do prefixo Location 3tenha o ^~modificador?

nginx
  • 1 1 respostas
  • 71 Views

1 respostas

  • Voted
  1. Best Answer
    Ivan Shatsky
    2024-11-29T19:18:42+08:002024-11-29T19:18:42+08:00

    Isso acontece porque o algoritmo real para selecionar um local no nginx difere do que está descrito na documentação. Ou, para ser mais específico, a documentação oficial não explica o processo de seleção de local para locais aninhados, o que é consideravelmente mais complexo. Até agora, não encontrei nenhum artigo em inglês explicando como ele realmente funciona, então aqui está minha tentativa de esclarecê-lo.

    Vamos começar com a configuração fornecida na pergunta original:

    location / {
        return 200 "Location 1\n";
    }
    location ~ \.php$ {
        return 200 "Location 2\n";
    }
    location /tmp {
        return 200 "Location 3\n";
        location ~ \.php$ {
            return 200 "Location 3a\n";
        }
    }
    

    Pode-se pensar que a solicitação /tmp/foo.phpserá processada com location ~ \.php$ { ... }(marcado como "Local 2"), pois a documentação diz explicitamente:

    Para encontrar o local que corresponde a uma determinada solicitação, o nginx primeiro verifica os locais definidos usando as strings de prefixo (locais de prefixo). Entre eles, o local com o maior prefixo correspondente é selecionado e lembrado. Em seguida, as expressões regulares são verificadas, na ordem em que aparecem no arquivo de configuração. A busca de expressões regulares termina na primeira correspondência, e a configuração correspondente é usada.

    Vamos verificar:

    > curl http://127.0.0.1/tmp/foo.php
    Location 3a
    

    Inesperado, não é? O que a documentação não diz é que, após identificar o local de prefixo correspondente mais longo, o nginx inicia uma nova iteração de busca sobre seus locais aninhados, se houver. Esse processo continua recursivamente: em cada etapa, as mesmas regras de correspondência são aplicadas e, se um local de regex aninhado correspondente for encontrado, enquanto nenhum local de prefixo mais longo aninhado for correspondido, o nginx interrompe a busca e usa esse local para manipular a solicitação.

    No nosso exemplo, para a /tmp/foo.phpsolicitação:

    1. O Nginx primeiro identifica o local do prefixo correspondente mais longo location /tmp { ... }(marcado como "Local 3").
    2. Uma nova iteração de pesquisa começa em seus locais aninhados.
    3. O aninhado location ~ \.php$ { ... }(marcado como "Localização 3a") corresponde e é usado para manipular a solicitação.

    Agora, vamos estender a configuração adicionando um quarto local:

    location /tmp/foo {
        return 200 "Location 4\n";
    }
    

    Testando a mesma solicitação:

    > curl http://127.0.0.1/tmp/foo.php
    Location 2
    

    O que aconteceu aqui?

    1. Na primeira etapa, o maior prefixo correspondente é location /tmp/foo { ... }.
    2. Como não há locais aninhados, o nginx avalia os locais das expressões regulares no mesmo nível.
    3. O local da expressão regular location ~ \.php$ { ... }corresponde e é usado para manipular a solicitação.

    Outras solicitações como essas /tmp/bar.phpcontinuam sendo processadas como antes:

    > curl http://127.0.0.1/tmp/bar.php
    Location 3a
    

    Em seguida, vamos modificar a configuração novamente, movendo o location /tmp/foo { ... }para dentro do location /tmp { ... }:

    location / {
        return 200 "Location 1\n";
    }
    location ~ \.php$ {
        return 200 "Location 2\n";
    }
    location /tmp {
        return 200 "Location 3\n";
        location ~ \.php$ {
            return 200 "Location 3a\n";
        }
        location /tmp/foo {
            return 200 "Location 3b\n";
        }
    }
    

    Executando alguns testes:

    > curl http://127.0.0.1/tmp/foo.php
    Location 3a
    > curl http://127.0.0.1/tmp/foo.html
    Location 3b
    

    Nada inesperado até agora.

    Agora, vamos examinar o ^~modificador de diretiva location. De acordo com a documentação:

    Se o local do prefixo correspondente mais longo tiver o ^~modificador, as expressões regulares não serão verificadas.

    Vamos verificar usando a seguinte configuração:

    location / {
        return 200 "Location 1\n";
    }
    location ~ \.php$ {
        return 200 "Location 2\n";
    }
    location /tmp {
        return 200 "Location 3\n";
        location ~ \.php$ {
            return 200 "Location 3a\n";
        }
    }
    location ^~ /tmp/foo {
        return 200 "Location 4\n";
    }
    

    Executando alguns testes:

    > curl http://127.0.0.1/tmp/foo.php
    Location 4
    > curl http://127.0.0.1/tmp/foo.html
    Location 4
    > curl http://127.0.0.1/tmp/bar.php
    Location 3a
    > curl http://127.0.0.1/tmp/bar.html
    Location 3
    

    Parece que tudo funciona como esperado. O ^~modificador on location ^~ /tmp/foo { ... }garante que os mesmos locais de regex de nível, como location ~ \.php$ { ... }, não possam ultrapassar solicitações correspondentes como /tmp/foo.php.

    Agora, aqui está algo que pode realmente surpreender você. Vamos modificar nossa configuração, movendo o location ^~ /tmp/foo { ... }para dentro location /tmp { ... }novamente:

    location / {
        return 200 "Location 1\n";
    }
    location ~ \.php$ {
        return 200 "Location 2\n";
    }
    location /tmp {
        return 200 "Location 3\n";
        location ~ \.php$ {
            return 200 "Location 3a\n";
        }
        location ^~ /tmp/foo {
            return 200 "Location 3b\n";
        }
    }
    

    Vamos testar a mesma /tmp/foo.phpsolicitação. Você está esperando que a resposta seja Location 3b, certo?

    > curl http://127.0.0.1/tmp/foo.php
    Location 2
    

    Oops... Parece estranho, não é? Bem, esse é provavelmente o último aspecto do algoritmo que precisa ser explicado. Após identificar o local de prefixo correspondente mais longo no nível mais aninhado (no nosso caso, o location ^~ /tmp/foo { ... }, marcado como "Localização 3b"), se nenhum local de regex correspondente for encontrado dentro dele, o nginx lembra desse local e começa a subir a árvore de configuração de volta ao nível mais externo. Em cada nível que ele passa durante a subida, as seguintes ações são tomadas:

    • Se o local de prefixo correspondente mais longo no nível atual não tiver um ^~modificador, o nginx corresponde à solicitação em relação a todos os locais de regex definidos naquele nível. O primeiro local de regex correspondente, se houver, é usado para manipular a solicitação; caso contrário, o nginx continua ascendente.
    • Se o local de prefixo correspondente mais longo no nível atual tiver um ^~modificador, o nginx pula a correspondência da solicitação com os locais de regex definidos naquele nível e imediatamente sobe para o próximo nível acima. Se ele já tiver atingido o nível mais externo, o local de prefixo correspondente mais longo lembrado do nível mais aninhado é usado para manipular a solicitação.

    É isso. Ter o ^~modificador em um local de prefixo aninhado (localização 3b) não garante que a solicitação não será ultrapassada por um local de regex externo (localização 2) se o local de prefixo correspondente mais longo externo (localização 3) não tiver ^~modificador.

    PS Claro, deve ser mencionado que se um local de correspondência exata (um local com o =modificador) for encontrado em qualquer nível durante a descida, o nginx para imediatamente de procurar, e o local encontrado é usado para manipular a solicitação. Considerando isso, uma configuração típica do nginx como

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/path/to/php-fpm/socket;
    }
    

    pode ser significativamente otimizado se o index.phparquivo for o único manipulador das solicitações, o que é comum em muitos casos de uso:

    location = /index.php {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/path/to/php-fpm/socket;
    }
    
    • 3

relate perguntas

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Você pode passar usuário/passar para autenticação básica HTTP em parâmetros de URL?

    • 5 respostas
  • Marko Smith

    Ping uma porta específica

    • 18 respostas
  • Marko Smith

    Verifique se a porta está aberta ou fechada em um servidor Linux?

    • 7 respostas
  • Marko Smith

    Como automatizar o login SSH com senha?

    • 10 respostas
  • Marko Smith

    Como posso dizer ao Git para Windows onde encontrar minha chave RSA privada?

    • 30 respostas
  • Marko Smith

    Qual é o nome de usuário/senha de superusuário padrão para postgres após uma nova instalação?

    • 5 respostas
  • Marko Smith

    Qual porta o SFTP usa?

    • 6 respostas
  • Marko Smith

    Linha de comando para listar usuários em um grupo do Windows Active Directory?

    • 9 respostas
  • Marko Smith

    O que é um arquivo Pem e como ele difere de outros formatos de arquivo de chave gerada pelo OpenSSL?

    • 3 respostas
  • Marko Smith

    Como determinar se uma variável bash está vazia?

    • 15 respostas
  • Martin Hope
    Davie Ping uma porta específica 2009-10-09 01:57:50 +0800 CST
  • Martin Hope
    kernel O scp pode copiar diretórios recursivamente? 2011-04-29 20:24:45 +0800 CST
  • Martin Hope
    Robert ssh retorna "Proprietário incorreto ou permissões em ~/.ssh/config" 2011-03-30 10:15:48 +0800 CST
  • Martin Hope
    Eonil Como automatizar o login SSH com senha? 2011-03-02 03:07:12 +0800 CST
  • Martin Hope
    gunwin Como lidar com um servidor comprometido? 2011-01-03 13:31:27 +0800 CST
  • Martin Hope
    Tom Feiner Como posso classificar a saída du -h por tamanho 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich O que é um arquivo Pem e como ele difere de outros formatos de arquivo de chave gerada pelo OpenSSL? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent Como determinar se uma variável bash está vazia? 2009-05-13 09:54:48 +0800 CST

Hot tag

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve