Вопрос: Перенаправление Nginx через прокси, переписывание и сохранение URL-адреса


В Nginx мы пытаемся перенаправить URL-адрес следующим образом:

http://example.com/some/path -> http://192.168.1.24

где пользователь по-прежнему видит исходный URL-адрес в своем браузере. Как только пользователь будет перенаправлен, скажите, что они нажимают на ссылку на /section/index.html, мы хотели бы, чтобы это сделало запрос, который приводит к перенаправлению

http://example.com/some/path/section/index.html -> http://192.168.1.24/section/index.html

и снова сохраните исходный URL.

Наши попытки включали различные решения с использованием прокси-серверов и правил перезаписи, а ниже показана конфигурация, которая приблизила нас к решению (обратите внимание, что это конфигурация веб-сервера для example.com веб сервер). Однако есть еще две проблемы:

  • Он неправильно выполняет переписывание, поскольку URL-адрес запроса, полученный веб-сервером http://192.168.1.24 включает /some/path и поэтому не выполняет требуемую страницу.
  • Когда вы наводите курсор на ссылку после того, как страница была подана, /some/path отсутствует в URL-адресе

    server {
        listen          80;
        server_name     www.example.com;
    
        location /some/path/ {
            proxy_pass http://192.168.1.24;
            proxy_redirect http://www.example.com/some/path http://192.168.1.24;
            proxy_set_header Host $host;
        }
    
        location / {
            index index.html;
            root  /var/www/example.com/htdocs;
        }
    }
    

Мы ищем решение, которое связано только с изменением конфигурации веб-сервера на example.com, Мы можем изменить конфигурацию на 192.168.1.24 (также Nginx), однако мы хотим попытаться избежать этого, потому что нам нужно будет повторить эту настройку для сотен разных серверов, доступ которых проксирован через example.com,


61
2018-04-04 00:49


Источник




Ответы:


Во-первых, вы не должны использовать root директива внутри блока местоположения, это плохая практика. В этом случае это не имеет значения.

Попробуйте добавить второй блок местоположения:

location ~ /some/path/(?<section>.+)/index.html {
    proxy_pass http://192.168.1.24/$section/index.html;
    proxy_set_header Host $host;
}

Это фиксирует часть после / some / path / и перед index.html переменной $ section, которая затем используется для установки назначения proxy_pass. Вы можете сделать регулярное выражение более конкретным, если потребуется.


54
2018-04-04 05:24



Извинения за поздний ответ - это так близко к достижению того, что мы ищем. Единственным недостатком является то, что после того, как целевая страница была отправлена, URL-адреса ссылок в браузере не включают в себя «/ some / path /», что означает, что они не работают, если пользователь нажимает на них. Если мы сможем решить, как преодолеть это, я буду обновлять и принимать этот ответ, так как он почти такой. - robjohncox
Ссылки, отображаемые браузером, генерируются программным обеспечением, работающим на сервере 192.168.1.24. Вы должны изменить это программное обеспечение, чтобы достичь желаемого. - Tero Kilkanen
не уверен, что я следую вашему предупреждению о корневом внутреннем блоке. чтение документации nginx - это правильный способ сделать материал. они предупреждают только о неверной практике из-за отсутствия корня по умолчанию вне всех местоположений. nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/... - guy mograbi
Ну, проще иметь правило не использовать root внутри location блок, то вы не получите неожиданного поведения для местоположений по умолчанию. Только если вам нужно изменить значение по умолчанию root для каждого места, то вы можете использовать его. - Tero Kilkanen
Что ты имеешь ввиду получает $ host как имя? Каков точный HTTP-заголовок, который был отправлен и что именно вы хотите отправить? - Tero Kilkanen


Вы должны использовать URI-часть в proxy_pass директивы. Кроме того, вы перепутали аргументы порядка proxy_redirect директивой, и, вероятно, вам это совсем не нужно. Nginx имеет разумные значения по умолчанию для этой директивы.

В этом случае location блок может быть очень простым:

location /some/path/ {
    proxy_pass http://192.168.1.24/;
    # note this slash  -----------^
    proxy_set_header Host $host;
}

55
2018-04-04 06:17



Извинения за поздний ответ - я пробовал это, и, к сожалению, это не работает для нашего прецедента. Проблема заключается в том, что когда запрос выполняется на целевом сервере, /some/path/ часть URL-адреса сохраняется в запросе, который не является допустимым URL-адресом (нам нужно также переписать URL-адрес, чтобы удалить его). - robjohncox
@robjohncox, что именно вы пробовали? - Alexey Ten
слэш помог мне. Теперь mydomain.com/some/path/* правильно проксирован до 192.168.1.24/*, а не 192.168.1.24/some/path/* - Vadimo
Могу ли я добавить комментарий «# note this slash» в этом ответе? Три ура за этот комментарий! - 8one6
Не уверен, как это работает для всех вас. Это то, чего я пытаюсь достичь. Однако, когда пользователь нажимает ссылку, которая будет перенаправлять, например. до 192.168.1.24/login на локальной службе, он перенаправляется на mydomain.com/login вместо mydomain.com/some/path/login - mueslo


Вы можете использовать следующую конфигурацию для 100% -ного бесшовного сопоставления между /some/path/ на интерфейсе и / на бэкэнде.

Обратите внимание, что это единственный ответ до сих пор, который также без проблем обеспечивал бы абсолютные пути генерации 404 Not Found ошибок при условии, что правильный HTTP Referer заголовок отправляется браузером, поэтому все эти gif должны продолжать загружаться без необходимости изменять базовый HTML (что не только дорого, но также не поддерживается без дополнительных модулей, которые не были скомпилированы по умолчанию).

location /some/path/ {
    proxy_pass http://192.168.1.24/; # note the trailing slash!
}
location / {
    error_page 404 = @404;
    return 404; # this would normally be `try_files` first
}
location @404 {
    add_header Vary Referer; # sadly, no effect on 404
    if ($http_referer ~ ://[^/]*(/some/path|/the/other)/) {
        return 302 $1$uri;
    }
    return 404 "Not Found\n";
}

Ты можешь найти полное доказательство концепции и минимально жизнеспособный продукт в пределах https://github.com/cnst/StackOverflow.cnst.nginx.conf репозиторий.

Вот тестовый прогон, подтверждающий, что все краевые случаи работают:

curl -v -H 'Referer: http://example.su/some/path/page.html' localhost:6586/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location
> GET /and/more.gif HTTP/1.1
> Referer: http://example.su/some/path/page.html
< HTTP/1.1 302 Moved Temporarily
< Location: http://localhost:6586/some/path/and/more.gif
< Vary: Referer

curl -v localhost:6586/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location
> GET /and/more.gif HTTP/1.1
< HTTP/1.1 404 Not Found

curl -v localhost:6586/some/path/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location -e uri
> GET /some/path/and/more.gif HTTP/1.1
< HTTP/1.1 200 OK
request_uri:    /and/more.gif

Постскриптум Если у вас есть много разных путей для сопоставления, то вместо выполнения регулярного сравнения $http_referer в пределах if в location @404, вы можете использовать глобальную map вместо этого.

Также обратите внимание, что конечные косые черты как в proxy_pass, так же хорошо как location он содержится в, являются весьма важными в соответствии с соответствующим ответом,

Рекомендации:


2
2017-08-27 03:42





Когда эта косая черта добавляется в проксированные джинкины nginx, вам представляется сообщение об ошибке «Кажется, что ваша обратная прокси настроена нарушена».

proxy_pass          http://localhost:8080/;

Remove this -----------------------------^

Он должен читать

proxy_pass          http://localhost:8080;

1
2018-05-04 15:44