IIS в качестве обратного прокси - сжатие перезаписанного ответа с бэкэнд-сервера

18

Я реализую обратный прокси для запросов на маршрутизацию на серверный сервер.

Функционально все работает правильно, однако я обеспокоен тем, что все ответы с сервера backend передаются клиенту (веб-браузеру) без сжатия.

Настройка выполняется следующим образом:

  • Сервер backend, недоступный для публики, во внутреннем домене. Принимает веб-приложение на https://internal.app
  • Передний веб-сервер с IIS 7.5, размещающий основной общедоступный веб-сайт и действующий как прокси-сервер для бэкэнд-сервера. Основной сайт находится в https://site.com .

Я хочу перенаправить все запросы на https://site.com/app/WHATEVER в https://internal.app/WHATEVER способом, прозрачным для клиентов.

Моя текущая настройка основана на расширении URL Rewrite 2.0 и Application Request Routing IIS. Общий подход основан на рекомендациях следующих статей:

Соответствующий раздел web.config site.com app:

<system.webServer>
    <rewrite>
        <rules>
            <rule name="Route the requests for backend app" stopProcessing="true">
                <match url="^app/(.*)" />
                <conditions>
                    <add input="{CACHE_URL}" pattern="^(https?)://" />
                </conditions>
                <action type="Rewrite" url="{C:1}://internal.app/{R:1}" />
                <serverVariables>
                    <set name="HTTP_ACCEPT_ENCODING" value="" />
                </serverVariables>
            </rule>
        </rules>
        <outboundRules>
            <rule name="RewriteBackendAbsoluteUrlsInResponse" preCondition="ResponseIsHtml1">
                <match filterByTags="A, Area, Base, Form, Frame, Head, IFrame, Img, Input, Link, Script" pattern="^http(s)?://internal.app(\:80)?/(.*)" />
                <action type="Rewrite" value="/app/{R:3}" />
            </rule>
            <rule name="RewriteBackendAbsoluteUrlsInRedirects" preCondition="ResponseIsHtml1">
                <match serverVariable="RESPONSE_LOCATION" pattern="^http(s)?://internal.app(\:80)?/(.*)" />
                <action type="Rewrite" value="/app/{R:3}" />
            </rule>
            <rule name="RewriteBackendRelativeUrlsInResponse" preCondition="ResponseIsHtml1">
                <match filterByTags="A, Area, Base, Form, Frame, Head, IFrame, Img, Input, Link, Script" pattern="^/(.*)" negate="false" />
                <conditions>
                    <add input="{URL}" pattern="^/app/.*" />
                </conditions>
                <action type="Rewrite" value="/app/{R:1}" />
            </rule>
            <rule name="RewriteBackendRelativeUrlsInRedirects" preCondition="ResponseIsHtml1">
                <match serverVariable="RESPONSE_LOCATION" pattern="^/(.*)" negate="false" />
                <conditions>
                    <add input="{URL}" pattern="^/app/.*" />
                </conditions>
                <action type="Rewrite" value="/app/{R:1}" />
            </rule>
            <preConditions>
                <preCondition name="ResponseIsHtml1">
                    <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
                </preCondition>
            </preConditions>
        </outboundRules>
    </rewrite>
    <urlCompression dynamicCompressionBeforeCache="false" />
</system.webServer>

Проблема заключается в том, что как только я перестаю очищать переменную сервера HTTP_ACCEPT_ENCODING , каждый запрос, соответствующий указанному выше правилу, заканчивается следующей ошибкой: HTTP Error 500.52 - URL Rewrite Module Error. Outbound rewrite rules cannot be applied when the content of the HTTP response is encoded ("gzip").

Я знаю этот поток , и я следил за этими инструкциями. Я установил dynamicCompressionBeforeCache="false" , как видно выше, я добавил необходимую запись в реестр, и я заверил, что модули находятся в правильном порядке в IIS.

Однако, похоже, это работает только в том случае, если переписывание происходит в одном веб-приложении. Если я удалю вышеуказанные правила и добавлю простой (и соответствующие правила исходящего), чтобы переписать, например. /x/WHATEVER до всего /WHATEVER , все работает отлично, без необходимости очищать HTTP_ACCEPT_ENCODING - правило работает, и сжатие включено для перезаписанных запросов.

Но как только я снова добавлю свое правило, которое переписывает ответ на другое веб-приложение, и я не очищаю заголовок HTTP_ACCEPT_ENCODING , снова появляется ту же ошибку.

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

Однако я ожидал бы, что, поскольку модуль сжатия указан сверху списка модулей, окончательный перезаписанный ответ должен быть сжат независимо от того, откуда он произошел. Кажется, что IIS делает несколько ярлыков и возвращает ответ клиенту в обход модуля сжатия. Или заголовок HTTP_ACCEPT_ENCODING удаляется достаточно быстро, чтобы полностью отключить сжатие (не только для связи между серверами).

Итак, наконец, мой вопрос: есть ли способ сжать эти ответы?

    
задан Jakub Januszkiewicz 10.04.2013 в 14:44
источник

4 ответа

25

Я сам это понял.

Что нужно сделать, чтобы заставить его работать:

  • Заголовок Accept-Encoding должен быть удален до перенаправления запроса на серверный сервер, так что ответ можно переписать с использованием исходящих правил.
  • заголовок должен быть восстановлен дополнительным сопроводительным исходящим правилом, чтобы он присутствовал, когда модуль сжатия запускается до отправки ответа клиенту

Я решил сделать это вот так:

  • добавить новую переменную сервера в правило перезаписи, чтобы сохранить исходный заголовок, отправленный клиентом:

    <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
    

    (я положил его перед строкой, которая очищает переменную HTTP_ACCEPT_ENCODING )

  • добавить новое исходящее правило:

    <rule name="RestoreAcceptEncoding" preCondition="NeedsRestoringAcceptEncoding">
      <match serverVariable="HTTP_ACCEPT_ENCODING" pattern="^(.*)" />
      <action type="Rewrite" value="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" />
    </rule>
    

    и сопутствующим предварительным условием:

    <preCondition name="NeedsRestoringAcceptEncoding">
      <add input="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" pattern=".+" />
    </preCondition>
    

Пока работает как прелесть.

    
ответ дан Jakub Januszkiewicz 10.04.2013 в 23:20
источник
  • Спасибо, я написал о вашем ответе здесь: anjdreas.blogspot.no/2016/01/... –  angularsen 31.01.2016 в 23:31
  • Рад, что вы нашли это полезным и спасибо за ссылку сюда! –  Jakub Januszkiewicz 01.02.2016 в 09:13
  • Хм, я чувствую, что мне не хватает части вашей формулы. У меня все это на месте, но я все еще не вижу сжатия для прокси-контента. Каков порядок ваших модулей IIS? Имеет ли значение, где HttpCacheModule и RewriteModule относятся к DynamicCompressionModule и StaticCompressionModule? –  Paul d'Aoust 01.03.2016 в 18:24
  • @ Pauld'Aoust Это было давно, и я больше не участвую в проекте, где я использовал это, поэтому не могу точно сказать, но связанный с ним поток указывает, что порядок модулей действительно имеет значение , –  Jakub Januszkiewicz 01.03.2016 в 22:18
  • Хотя это решение устраняет эту ошибку 500.53, описанную в OP, она эффективно удаляет сжатие gzip из ответа. Это может быть приемлемым, но следует отметить, что если сжатие gzip является желаемым результатом, это решение не предусматривает, что –  Scot 28.10.2016 в 23:14
2

Чтобы устранить проблему с оригинальным плакатом, а все еще сохраняя сжатые ответы gzip , нужно просто выполнить следующее:

  1. обновите реестр на своем общедоступном веб-сервере как таковой:

    а. Для 64-битных веб-сайтов запустите в командной консоли с правами администратора: reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InetStp\Rewrite /v LogRewrittenUrlEnabled /t REG_DWORD /d 0

    б. Для 32-битных веб-сайтов запустите в командной консоли с правами администратора: reg add HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432node\Microsoft\Inetstp\Rewrite /v LogRewrittenUrlEnabled /t REG_DWORD /d 0

  2. сбросить IIS

  3. отключить статическое сжатие

    а. для этого я вставил следующую свою веб-конфигурацию: <urlCompression doStaticCompression="false" doDynamicCompression="true" dynamicCompressionBeforeCache="false" />

  4. в узле сервера в диспетчере IIS, дважды щелкните значок Modules , затем справа щелкните «Просмотреть упорядоченный список» и убедитесь, что ваши статические / динамические модули сжатия находятся вверху и URL-адрес модуль перезаписи находится в нижней части

Обратите внимание

Я вижу множество решений по этой проблеме, плавающих вокруг сети, где заголовок запроса HTTP_CONTENT_TYPE очищается как часть правила перезаписи URL (включая ответы на этой странице). Следует помнить, что, хотя это устраняет исходную проблему с ошибкой 500.52, сжатие gzip в ответе УДАЛЕНО . Это может быть желаемым результатом, но если требуется сжатие gzip, вышеупомянутое решение выполнит трюк

    
ответ дан Scot 28.10.2016 в 23:11
источник
1

PS: Решение ниже работает только в том случае, если у вас есть контроль над сервером приложений.

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

Если вы отключите сжатие на сервере приложений, ответ, который вы получаете с сервера приложений, несжатый. На веб-сервере вы должны включить сжатие, поэтому веб-сервер будет соблюдать HTTP-заголовок «Accept-Encoding: gzip, deflate» при ответе на клиента (браузер).

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

    
ответ дан Gunawan Deng 18.05.2016 в 05:03
источник
  • Это сработало для меня, спасибо. Вот страница документации для изменения этих параметров в IIS: iis.net/configreference/system.webserver/httpcompression –  Ham Sam 16.01.2017 в 08:55
1

Просто добавление тега «serverVariables» в правиле перезаписи сделало трюк для меня:

<rewrite>
        <rules>
            <rule name="ReverseProxyInboundRule1" stopProcessing="true">
                <match url="(.*)" />
                <action type="Rewrite" url="http://otherurl{R:1}" />

                <serverVariables>
                    <set name="HTTP_ACCEPT_ENCODING" value="" />
                </serverVariables>
            </rule>

       </rules>
</rewrite>
    
ответ дан Marcio Fonseca 29.09.2016 в 17:53
источник