【问题标题】:IIS as a reverse proxy - compression of rewritten response from backend serverIIS 作为反向代理 - 压缩来自后端服务器的重写响应
【发布时间】:2013-04-10 12:44:22
【问题描述】:

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

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

设置如下:

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

我想以对客户端透明的方式将所有请求路由到 https://site.com/app/WHATEVERhttps://internal.app/WHATEVER

我当前的设置基于 URL Rewrite 2.0 和应用程序请求路由 IIS 扩展。一般方法基于以下文章中的指南:

site.com 应用程序的web.config 的相关部分:

<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 中的顺序正确。

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

但是,一旦我重新添加将响应重写到不同 Web 应用程序的规则,并且我没有清除 HTTP_ACCEPT_ENCODING 标头,就会再次出现相同的错误。

据我了解,如果重写涉及另一个 Web 应用程序,那么可以做什么会受到更多限制。例如。 URL 重写器必须从后端服务器接收未压缩的响应,以便能够使用出站规则对其进行重写。我想在这种情况下清除 HTTP_ACCEPT_ENCODING 是必须的。

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

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

【问题讨论】:

    标签: asp.net iis reverse-proxy http-compression arr


    【解决方案1】:

    我自己想通了。

    需要做什么才能使其正常工作:

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

    到目前为止就像一个魅力。

    【讨论】:

    • 很高兴您发现这很有用,并感谢您在此处链接!
    • 嗯,我觉得我错过了你的公式的一部分。我已经准备好所有这些东西,但我仍然没有看到代理内容的任何压缩。您的 IIS 模块的顺序是什么? HttpCacheModuleRewriteModuleDynamicCompressionModuleStaticCompressionModule 的关系是否重要?
    • @Pauld'Aoust 好久没参与用这个的项目了,所以不能确定,但​​是the thread I linked to表示模块的顺序确实很重要。
    • @JakubJanuszkiewicz 感谢您抽出宝贵时间回复!我最终走了另一条路(查看了我们应用程序的代码,发现我不需要重写响应正文,所以我只保留了 HTTP_ACCEPT_ENCODING 标头)。
    • 虽然此解决方案解决了 OP 中描述的这个 500.53 错误,但它实际上是从响应中删除了 gzip 压缩。这可能是可以接受的,但应该注意的是,如果 gzip 压缩是所需的结果,则此解决方案不提供此功能
    【解决方案2】:

    要在仍然保留 gzip 压缩响应的同时解决原始发帖者的问题,只需执行以下操作:

    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. 禁用静态压缩

      一个。为此,我插入了以下我的网络配置:&lt;urlCompression doStaticCompression="false" doDynamicCompression="true" dynamicCompressionBeforeCache="false" /&gt;

    4. 在 IIS 管理器的服务器节点中,双击Modules 图标,然后在右侧,单击“查看有序列表”并验证您的静态/动态压缩模块是否朝向顶部和 URL重写模块是朝向底部的

    请注意

    我看到网上有很多解决这个问题的方法,其中 HTTP_CONTENT_TYPE 请求标头作为 URL 重写规则的一部分被清除(包括此页面上的答案)。应该知道,虽然这确实解决了 500.52 错误的原始问题,但响应上的 gzip 压缩是 REMOVED。这可能是我们想要的结果,但如果需要 gzip 压缩,上述解决方案就可以解决问题

    【讨论】:

    • 你能解释一下为什么这会起作用,以及它是否不会在未来版本的 URL Rewrite 中中断?您不是使用LogRewrittenUrlEnabled 注册表值的副作用来完成重写压缩响应吗?
    【解决方案3】:

    PS:以下解决方案仅在您可以控制您的应用服务器时才有效。

    它基本上是让 Web 服务器进行压缩,并让应用服务器完成应用程序应该做的重任(不压缩)。

    如果您在应用服务器上禁用压缩,您从应用服务器获得的响应是​​未压缩的。在 Web 服务器上,您应该启用压缩,因此 Web 服务器在响应客户端(浏览器)时将遵循 HTTP 标头“Accept-Encoding: gzip,deflate”。

    此配置将卸载应用服务器上的 CPU,但会增加您的 Web 服务器和应用服务器之间的网络流量。如果您在内部网络上,它不会对性能产生太大影响。

    【讨论】:

    【解决方案4】:

    只需在重写规则中添加“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>
    

    【讨论】:

      猜你喜欢
      • 2011-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-16
      相关资源
      最近更新 更多