IIS作为反向代理 - 压缩来自后端服务器的重写响应

Jak*_*icz 20 asp.net iis reverse-proxy http-compression arr

我正在实现一个反向代理,用于将请求路由到后端服务器.

功能上一切正常,但是我担心来自后端服务器的所有响应都会在没有压缩的情况下传输到客户端(Web浏览器).

设置如下:

  • 内部域上无法公开访问的后端服务器.托管Web应用程序https://internal.app
  • 带有IIS 7.5的前端Web服务器,托管主公共网站并充当后端服务器的代理.主要网站是https://site.com.

我想所有请求路由到https://site.com/app/WHATEVERhttps://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>
Run Code Online (Sandbox Code Playgroud)

问题是,一旦我停止清除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中的顺序正确.

但是,这似乎仅在重写发生在一个Web应用程序中时才起作用.如果我删除上述规则并添加一个简单的规则(以及相应的出站规则)来重写例如/x/WHATEVER只是/WHATEVER,所有工作都完美无需清除HTTP_ACCEPT_ENCODING- 规则可以正常工作,并且对重写的请求启用了压缩.

但是,只要我重新添加我的规则,将响应重写为其他Web应用程序,并且我不清除HTTP_ACCEPT_ENCODING标题,就会再次出现相同的错误.

根据我的理解,如果重写涉及另一个Web应用程序,那么可以做什么的约束更多.例如,URL重写器必须从后端服务器接收未压缩的响应,以便能够使用出站规则重写它.我想HTTP_ACCEPT_ENCODING在这种情况下清理是必须的,因为这个.

但是,我希望由于压缩模块列在模块列表的顶部,因此最终重写的响应应该被压缩,无论它来自何处.似乎IIS制作了一些快捷方式,并绕过压缩模块将响应返回给客户端.或者HTTP_ACCEPT_ENCODING很快删除标题以完全禁用压缩(不仅在服务器到服务器通信中).

最后,我的问题是:有没有办法压缩这些回复?

Jak*_*icz 28

我自己弄清楚了.

要使其工作,需要做些什么:

  • Accept-Encoding 必须先删除标头,然后才能将请求路由到后端服务器,以便可以使用出站规则重写响应
  • 必须通过附加的附带出站规则来恢复标头,以便在将响应发送到客户端之前压缩模块启动时存在

我决定这样做:

  • 将新的服务器变量添加到重写规则以保存客户端发送的原始标头:

    <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
    
    Run Code Online (Sandbox Code Playgroud)

    (我把它放在清除HTTP_ACCEPT_ENCODING变量的行之前)

  • 添加新的出站规则:

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

    以及一个附带的前提条件:

    <preCondition name="NeedsRestoringAcceptEncoding">
      <add input="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" pattern=".+" />
    </preCondition>
    
    Run Code Online (Sandbox Code Playgroud)

到目前为止,它就像一个魅力.

  • 虽然此解决方案解决了OP中描述的500.53错误,但它实际上是从响应中删除gzip压缩.这可能是可以接受的,但应该注意的是,如果gzip压缩是期望的结果,则该解决方案不提供 (4认同)