Как удалить путь с помощью nginx proxy_pass

77

У меня запущено веб-приложение http://example.com/и я хочу «смонтировать» другое приложение на отдельном сервере http://example.com/en. Восходящие серверы и, proxy_passкажется, работают, но для одной проблемы:

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location /en {
    proxy_pass http://luscious;
  }
}

При открытии example.com/enмое обратное приложение возвращается 404 not found /en. Это имеет смысл, поскольку восходящий поток не имеет пути /en.

Это proxy_pathправильное решение? Должен ли я переписать «upstream», чтобы он слушал /enвместо этого, как корневой путь? Или есть директива, которая позволяет мне переписать путь, переданный вверх по течению?

Беркеш
источник

Ответы:

134

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

location = /en {
    return 302 /en/;
}
location /en/ {
    proxy_pass http://luscious/;  # note the trailing slash here, it matters!
}
CNST
источник
1
Насколько я знаю, последняя часть все равно будет проходить "/ en" как путь к прокси, не так ли?
Беркес
15
@berkes, нет, это не будет - косая черта в этом proxy_pass- то, что имеет значение. Кроме того, этот ответ является более правильным, чем тот, который вы придумали, потому что он также гарантирует, что он proxy_redirectостается default, так что вы можете по-прежнему использовать 302et al в своем бэкэнде и работать правильно везде.
CNST
4
Ах, я пропустил косую черту :(
Вануан
3
Aaargh! ТРЕЙЛИНГ СЛЕШ!
Барримак
4
3 часа поисков, и да ... Это был завершающий удар. Спасибо друг!
Лукас П.
12

Я хотел бы обратиться к более новому ответу на основе регулярных выражений, популярность которого растет.

location ~ ^/en(/?)(.*)$ {  # OOPS!
  proxy_pass http://luscious/$2$is_args$args;  # OOPS!
}

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

  • Вышеупомянутое регулярное выражение будет соответствовать uri запроса /enjoy, перенаправляя его в /joyапстрим. Это действительно предназначено?

  • Запрос на /enне приведет к каким-либо перенаправлениям, непосредственно обслуживающим /от восходящего (почти как если бы запрос /en/был сделан вместо, но не совсем). Если вы используете относительные URI в своей корневой странице вверх по течению (иначе, почему бы вам не иметь /en/префикс прямо там, в восходящем URI?), Например src="style.css"(который может ссылаться на язык url("menu.png"), например), то браузер запросит как /style.cssвместо /en/style.css. (Или даже если вы везде используете абсолютные URI, что если кто-то ссылается на неясный полуобязательный ресурс относительно?) Ой, вдруг сайт может не работать, но только иногда или в крайних случаях.

  • Согласно моему предыдущему совету по другому вопросу, уже упомянутому в собственном ответе OP , использование регулярных выражений не дает proxy_redirectдирективе иметь значение по умолчанию default- offвместо этого ее значение уменьшается . Это означает, что если обратный поток ответит, Location: http://127.0.0.1:8080/en/dir/когда сделан запрос /en/dir, то это то, что увидит клиент, что, очевидно, не будет работать правильно. (Что было бы особенно иронично для /enзапроса, который в первую очередь побуждает использовать регулярные выражения, но эта конкретная реализация вместо этого страдает от другой проблемы, как уже упоминалось выше.) Плюс, если вы уже используетеupstreamДиректива, тогда это может стать очень уродливым, если вы просто попытаетесь использовать пользовательский, особенно если у вас может быть более одного вышестоящего сервера - как у вас есть отдельный proxy_redirectдля каждого из них? Вы также можете использовать регулярные выражения внутри proxy_redirect, возможно, даже для соответствия любому хосту, но что тогда, если вы решите дать междоменное перенаправление в будущем?

Чтобы попытаться обратиться к некоторым из указанных выше пунктов с помощью одного местоположения на основе регулярных выражений, мы могли бы сделать следующее (обратите внимание, что proxy_passнам также пришлось отбросить ссылку на сервер из upstreamдирективы на основе, чтобы сделать его proxy_redirectболее простым):

location ~ ^/en/?((?<=/).*)?$ {
  location = /en { return 302 /en/; }
  proxy_pass http://127.0.0.1:8080/$1$is_args$args;
  proxy_redirect http://127.0.0.1:8080/ /en/;
}

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

CNST
источник
Это вызывает исключение:nginx: [emerg] location "/en" is outside location "^/en/?((?<=/).*
Атлан
1
@Athlan, это потому, что ты не должен использовать это с самого начала! Если вы все еще хотите, вы можете поместить это место за пределы регулярного выражения.
CNST
положив локализацию = / en снаружи работает очень хорошо! спасибо
Себастьян Уэббер
7

Итак, я нашел ответ на stackoverflow :

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location ~ ^/en(/?)(.*) {
    proxy_pass http://luscious/$2;
  }
}

В основном: передача регулярного выражения в местоположение и передача обратного ссылки по URL-адресу proxy_pass.

Беркеш
источник
Я думаю "proxy_pass luscious / $ ;" должно быть "proxy_pass luscious / $ 2 "
Zafer
1
@Зафер прав, приведенный выше ответ дал мне ошибку
Франк
Я изменил ответ, но у меня нет под рукой сервера, где я могу попробовать это, банкомат, поэтому он не проверен.
Беркес
0

Бухгалтерский учет в документы Nginx

Чтобы передать запрос прокси-серверу HTTP, в расположении указывается директива proxy_pass. Например:

location /some/path/ {
    proxy_pass http://www.example.com/link/;
}

Этот пример конфигурации приводит к передаче всех запросов, обработанных в этом местоположении, на прокси-сервер по указанному адресу. Этот адрес может быть указан как имя домена или IP-адрес. Адрес также может включать порт:

location ~ \.php {
    proxy_pass http://127.0.0.1:8000;
}

Обратите внимание, что в первом примере выше за адресом прокси-сервера следует URI, / link /. Если URI указан вместе с адресом, он заменяет часть URI запроса, которая соответствует параметру location. Например, здесь запрос с /some/path/page.html URI будет передан по адресу http://www.example.com/link/page.html . Если адрес указан без URI или невозможно определить часть URI, подлежащую замене, передается полный URI запроса (возможно, измененный).

Джефф
источник