Стратегии работы с URI при создании приложения, которое находится за обратным прокси - PullRequest
4 голосов
/ 17 декабря 2009

Я создаю приложение с автономным HTTP-сервером, к которому можно получить прямой доступ или установить обратный прокси-сервер (например, Apache mod_proxy).

Итак, допустим, мое приложение работает на порте 8080, и вы настроили свой Apache следующим образом:

ProxyPass /myapp http://localhost:8080
ProxyPassReverse /myapp http://localhost:8080

Это приведет к тому, что HTTP-запросы, поступающие на главный сервер Apache, которые отправляются на /myapp/*, будут перенаправлены на мое приложение. Если запрос приходит как GET /myapp/bar, мое приложение увидит GET /bar. Это так и должно быть.

Проблема, которая возникает, заключается в генерации URI, которые должны быть переведены из URI-пространства моего приложения для корректной работы через прокси-сервер (т. Е. С добавлением /myapp/).

Директива ProxyPassReverse заботится об обработке этого для URI в заголовках HTTP (перенаправления и т. Д.), Но это не обрабатывает URI в HTML, сгенерированном моим приложением, или в статических файлах и шаблонах.

Мне известны такие фильтры, как mod_proxy_html, но это нестандартный модуль Apache, и в любом случае такие фильтры могут быть недоступны для других интерфейсных веб-серверов, которые могут работать как обратный прокси.

Итак, я предложил несколько возможных стратегий:

  1. Требуется установить переменную среды где-нибудь, которая содержит путь прокси, и добавить ее ко всем сгенерированным URI. Это кажется не элегантным; это нарушает инкапсуляцию, обеспечиваемую обратным прокси.

  2. Поместите путь прокси в файл конфигурации для моего приложения. То же возражение, что и выше.

  3. Используйте только относительные URI в моем приложении. Это может быть несколько сложно; Мне нужно будет рассчитать разницу в пути между текущим ресурсом и тем, куда идет ссылка, и добавить соответствующее число ../. Кажется грязным Другая проблема заключается в том, что некоторые вещи должны генерировать абсолютные URI, такие как RSS-каналы и сгенерированные электронные письма.

  4. Используйте какой-нибудь хакерский Javascript на внешнем интерфейсе для манипулирования URI в тексте документа. Это кажется ужасной идеей с точки зрения взаимодействия.

  5. Используйте отдельную функцию генерации URI во всем моем коде и требуйте, чтобы через мою систему шаблонов запускались «статические» файлы, такие как Javascript, CSS и т. Д. Это идея, к которой я сейчас склоняюсь.

Это должно быть довольно распространенная проблема. Как вы подошли к этому в прошлом? Что сработало и что усложнило ситуацию?

1 Ответ

7 голосов
/ 20 декабря 2009

Да, общая проблема. Как это решить, зависит от типа вашего приложения, серверной платформы и веб-фреймворка, с которым вы работаете. Но есть общий подход к решению этих проблем, который до сих пор работал довольно хорошо.

Я предпочитаю обрабатывать подобные проблемы в коде приложения, а не полагаться на такие модули веб-сервера, как mod_proxy_html, потому что часто бывает слишком много особых случаев (например, сборка URL-адресов на стороне клиента на JavaScript), которые серверный модуль не ловит. Тем не менее, в некоторых случаях я прибегал к подходу сервер-модуль, но я решил сам пересмотреть код модуля для обработки угловых случаев. Также имейте в виду исполнение; Исправление URL-адресов в вашем коде в то время, когда они генерируются, обычно быстрее, чем проталкивание всего HTML-кода через другой серверный модуль.

Вот моя рекомендация о том, как справиться с этим в вашем коде:

Сначала вам нужно выяснить, какие URL генерировать. Я предпочитаю относительные URL. Вы правы выше, что «добавить соответствующее количество ../'es» грязно, но по крайней мере это ваш (программист) беспорядок. Если вы воспользуетесь подходом config-file / environment-variable, то вы будете зависеть от того, кто развернет ваше приложение (например, недоплаченный и раздражительный инженер по ИТ-операциям), чтобы всегда правильно все настраивать. Это также усложняет выпуск вашего кода, даже если вы выполняете развертывание самостоятельно, поскольку вы не можете просто скопировать свои файлы разработки в производственную среду, но должны добавить пользовательский шаг для среды развертывания. В прошлом я обнаружил, что устранение потенциальных проблем развертывания стоит много упреждающего кодирования.

Затем вам нужно вставить эти URL в ваш код. Как вы это делаете, зависит от типа контента / кода:

Для серверного кода (например, PHP, RoR и т. Д.) Вы должны убедиться, что генерация URL-адреса на стороне сервера происходит в как можно меньшем количестве мест в вашем коде (в идеале, один метод!). Если вы используете какую-либо основную веб-инфраструктуру MVC (например, RoR, Django и т. Д.), Это должно быть тривиально, поскольку генерация URL с использованием инфраструктуры MVC уже обычно проходит через единственный путь кода, который вы можете переопределить. Если вы не используете ни одну из этих платформ, вам, вероятно, придется помешать генерации URL по всему коду. Но подход, который вы захотите использовать, состоит в том, чтобы сгенерировать все URL-адреса с помощью кода, а затем переопределить этот метод для поддержки преобразования не относительных URL-адресов в относительные URL-адреса. Обычно вы можете искать шаблоны в вашем коде (например, "/, '/, "http://, 'http://) и выполнять поиск и замену вручную (или, если вы действительно занудный и терпеливее, чем я, создайте регулярное выражение для замены каждого общего случая в вашем исходном коде).

Ключ к тому, чтобы сделать эту работу надежной, заключается в том, что вместо ручной замены всех абсолютных URL-адресов на относительные в вашем коде на стороне сервера (который, даже если вы правильно делаете каждый из них, хрупок при перемещении файлов), можете оставить абсолютные URL-адреса на месте и просто обернуть их вызовом вашего метода «релятивизатора». Это гораздо надежнее и ломче.

Для Javascript я обычно хотел бы сделать то же самое, что и код сервера - перенести все генерации URL в один метод и убедиться, что любая генерация URL вызывает этот метод. Это может быть сложно в приложении с большим количеством уже существующих javascript, но описанный выше метод поиска и замены, похоже, хорошо работает и в JS.

Для CSS URL-адреса в CSS относятся к расположению CSS-файла (не к HTML-странице вызова), поэтому использование относительных URL-адресов обычно легко. Просто поместите свой CSS в папку и либо поместите изображения в более глубокие папки под ним, либо поместите изображения в параллельную папку с вашим CSS и используйте один ../, чтобы добраться до изображений относительно. В общем, это хорошая рекомендация - если вы еще не делали относительные URL в CSS, вам следует подумать об этом независимо от обратного прокси-сервера.

Наконец, вам нужно выяснить, что делать с другими странными статическими файлами (например, старые статические HTML-файлы иногда появляются). В общем, я рекомендую ту же практику, что и CSS и изображения - в идеале вы бы помещали статические файлы в предсказуемые каталоги и полагались на относительные URL-адреса. Или (в зависимости от вашей серверной платформы) может быть проще переназначить расширения этих статических файлов, чтобы они обрабатывались вашей веб-структурой, а затем запустить генератор URL-адресов на стороне сервера для всех URL-адресов. Или, исключая это, вы можете оставить файлы на месте и вручную исправить URL-адреса, чтобы они были относительными - зная, что это хрупко.

Пройдя полный круг, иногда слишком много мест, где генерируются URL, и более эффективно использовать серверный модуль, такой как mod_proxy_html. Но я считаю это последним средством, особенно если вам не удобно редактировать исходный код, если это необходимо.

Кстати, я понимаю, что ничего не упомянул о вашей идее # 4 выше (javascript-link-fixup). Я бы не стал этого делать - если у пользователя отключен JavaScript или (что более распространено), какая-то проблема с сетью мешает этому JavaScript в течение некоторого времени после загрузки остальной части страницы, тогда ваши ссылки не будут работать Слишком рискованно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...