2013-04-10 12 views
18

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

Функционально все работает правильно, однако я обеспокоен тем, что все ответы с сервера 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 приложения:

<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").

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

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

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

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

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

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

ответ

24

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

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

  • 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> 
    

работает как шарм до сих пор.

+0

Спасибо, я написал о вашем ответе здесь: http://anjdreas.blogspot.no/2016/01/iis-aspnet- exposing-localhost-to-world.html – angularsen

+0

Рад, что вы нашли это полезным и спасибо за ссылку сюда! –

+1

Хм, я чувствую, что мне не хватает части вашей формулы. У меня все это на месте, но я все еще не вижу сжатия для прокси-контента. Каков порядок ваших модулей IIS? Имеет ли значение, где «HttpCacheModule» и «RewriteModule» относятся к «DynamicCompressionModule» и «StaticCompressionModule»? –

1

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

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

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

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

+0

Это сработало для меня, спасибо. Вот страница документации для изменения этих параметров в IIS: https://www.iis.net/configreference/system.webserver/httpcompression –

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> 
2

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

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

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

    b. Для 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, вышеупомянутое решение сделает трюк