Это моя конфигурация 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 и использовать в прокси_проходят.
Прежде всего, ваше регулярное выражение ^/(123[0-9])$
будет /1234
URI (или /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;
}
Если вам необходимо обслужить какой-либо запрос /
, как указано выше, вы должны использовать следующий блок местоположения, чтобы убедиться, что ваш переписанный 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;
}
Эта конфигурация должна быть полностью работоспособной (наконец-то). И еще раз, если вам нужно обслужить какой-либо запрос /
, как указано выше, вместо этого вы должны использовать следующий блок местоположения:
location ~ ^/(?<port>123[0-9])(?:/|$) {
rewrite "^/\d{4}(?:/(.*))?" /$1 break;
proxy_pass http://127.0.0.1:$port;
}