Использование части URI в качестве номера порта для прокси-сервера nginx_директива pass

Это моя конфигурация nginx:

server {
        listen 443 ssl;
        server_name sub.example.fr ;
        location ~ ^/ (123[0-9])$ { # regex work
                #rewrite ^/[0-9]{4}(.*)$ $1 last; # do not work, with last or break
                #proxy_pass http://localhost:$1/; # add slash not allow
                proxy_pass http://localhost:$1;
        }
}

Я хочу перенаправить https://sub.example.fr/1234на http://localhost:1234, поэтому я просто хочу извлечь номер порта, удалить его из URL и использовать в прокси_проходят.

0
задан 19 October 2021 в 07:43
1 ответ

Прежде всего, ваше регулярное выражение ^/(123[0-9])$будет /1234URI (или /1230, /1231и т. д.), но не /1234/some/path, поскольку вы используя привязку конца строки $. Я предполагаю, что это не ошибка, а дизайнерское решение. Если это не так, чтобы соответствовать как /1234, так и /1234/some/path(но не что-то вроде /12345), вы можете использовать чередование : ^/(123[0-9])(?:/|$)(здесь я использую группу без захвата (?:...), как считается, что он имеет немного лучшую производительность, чем группа захвата).

В вашей конфигурации есть целая куча различных ошибок. Давайте рассмотрим каждый.

Ошибка №1: неправильное использование rewrite ... last;.

Действительно, вы не можете указать URI для proxy_passвосходящего потока, как вы пытаетесь сделать с завершающей косой чертой

proxy_pass http://localhost:$1/; # add slash not allow

внутри местоположений, совпадающих с регулярным выражением (а также внутри именованных местоположений), и единственным способ изменить URI, который будет передан серверной части, — использовать директиву rewrite. Однако правильный способ изменить URI внутри блока locationдля его последующей обработки в том же месте — использовать rewrite ... break; , поскольку rewrite ... last ;заставит nginx искать новое место для переписанного URI. Это означает, что нам нужно использовать флаг breakдля директивы rewrite:

rewrite ^/[0-9]{4}(.*)$ $1 break;

Осторожно! Никакие директивы изngx_http_rewrite_moduleне будут выполняться после rewrite ... break;(или просто break;) директивы ( update: после некоторого тестирования, вопреки тому, что сказано в документации , оказалось, что это верно только для директивыbreak , но не rewrite ... breakодин, по крайней мере, для OpenResty 1.17.8.2 на базе ядра nginx 17.8).

Ошибка №2: Вы должны заключать в кавычки любую строку, содержащую фигурные скобки, иначе они будут считаться блоком конфигурации nginx.

Предыдущая директива выдаст нам следующую ошибку:

nginx: [emerg] директива «rewrite» не заканчивается «;»

Чтобы избавиться от этой ошибки, нам нужно заключить наш шаблон регулярного выражения в кавычки из-за использования фигурных скобок:

rewrite "^/[0-9]{4}(.*)$" $1 break;

Ошибка №3: ​​Нумерованные захваты перезаписываются всякий раз, когда вычисляется регулярное выражение.

Предположим, что у вас есть URI /1234:

location ~ ^/(123[0-9])$ {
    # Here the value of '$1' variable is "1234"
    rewrite "^/[0-9]{4}(.*)$" $1 break;
    # Here the value of '$1' variable is an empty string!
    proxy_pass http://localhost:$1; # There will be no port for 'proxy_pass' directive
}

Вы можете сохранить это значение $1до того, как правило перезаписи вычислит собственное регулярное выражение, используянабор . ] директива:

location ~ ^/(123[0-9])$ {
    set $port $1;
    rewrite "^/[0-9]{4}(.*)$" $1 break;
    proxy_pass http://localhost:$port;
}

или лучше использовать именованную группу захвата:

location ~ ^/(?<port>123[0-9])$ {
    rewrite "^/[0-9]{4}(.*)$" $1 break;
    proxy_pass http://localhost:$port;
}

Иногда не может быть другого решения, кроме как использовать именованные захваты, отличный пример такой ситуации приведен в this резьба.

Ошибка №4: Переписанный URI не может быть пустой строкой.

Опять же, давайте предположим, что у вас есть URI /1234. После правила перезаписи внутренняя переменная nginx$uriбудет иметь пустое значение. Это приведет к ошибке внутреннего сервера HTTP 500, и в журнале ошибок nginx вы увидите следующее сообщение об ошибке:

перезаписанный URI имеет нулевую длину

. Чтобы устранить эту ошибку, просто перепишите любой URI на /:

location ~ ^/(?<port>123[0-9])$ {
    rewrite ^ / break;
    proxy_pass http://localhost:$port;
}

Если вам необходимо обслужить какой-либо запрос //some/path, как указано выше, вы должны использовать следующий блок местоположения, чтобы убедиться, что ваш переписанный URI начинается с косой черты. :

location ~ ^/(?<port>123[0-9])(?:/|$) {
    rewrite "^/\d{4}(?:/(.*))?" /$1 break;
    proxy_pass http://localhost:$port;
}

Ошибка №5: При использовании переменных с директивой proxy_passнеобходимо указывать резолвер.

Приведенная выше конфигурация близка к рабочему решению.Однако он по-прежнему не работает, что приводит к ошибке HTTP 502 Bad Gateway. Вам необходимо указать преобразователь, когда вы используете переменные с директивой proxy_passи ваш апстрим указывается доменным именем, а не IP-адресом, иначе вы получите следующую ошибку в ваш журнал ошибок nginx:

не определен преобразователь для разрешения localhost

Обычно вам нужно использовать что-то вроде

resolver 8.8.8.8;
location ~ ^/(?<port>123[0-9])$ {
    rewrite ^ / break;
    proxy_pass http://localhost:$port;
}

, но поскольку ваш восходящий поток — localhost,вы можете указать его IP-адрес вместо имени домена, таким образом, вам вообще не понадобится эта директива resolver:

location ~ ^/(?<port>123[0-9])$ {
    rewrite ^ / break;
    proxy_pass http://127.0.0.1:$port;
}

Эта конфигурация должна быть полностью работоспособной (наконец-то). И еще раз, если вам нужно обслужить какой-либо запрос //some/path, как указано выше, вместо этого вы должны использовать следующий блок местоположения:

location ~ ^/(?<port>123[0-9])(?:/|$) {
    rewrite "^/\d{4}(?:/(.*))?" /$1 break;
    proxy_pass http://127.0.0.1:$port;
}
1
ответ дан 19 October 2021 в 12:29

Теги

Похожие вопросы