首页 文章

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

提问于
浏览
18

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

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

设置如下:

  • 内部域上无法公开访问的后端服务器 . 在 https://internal.app 上托管Web应用程序

  • 使用IIS 7.5的前端Web服务器,托管主公共网站并充当后端服务器的代理 . 主站点位于 https://site.com .

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

我当前的设置基于URL Rewrite 2.0和Application Request Routing IIS扩展 . 一般方法基于以下文章的指导原则:

site.com app的 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 Headers ,就会再次出现相同的错误 .

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

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

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

4 回答

  • 1

    我自己弄清楚了 .

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

    在将请求路由到后端服务器之前必须删除

    • Accept-Encoding 标头,以便可以使用出站规则重写响应

    • the header must be restored by an additional accompanying outbound rule, so that it is present when the compression module kicks in before the response is sent to the client

    我决定这样做:

    • 将新的服务器变量添加到重写规则以保存客户端发送的原始标头:
    <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>
    

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

  • 25

    为了解决原始海报的问题,同时仍然保留gzip压缩响应,只需要执行以下操作:

    • 更新面向公众的Web服务器上的注册表:

    一个 . 对于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

    • 重置IIS

    • 禁用静态压缩

    一个 . 为了实现这一点,我插入了以下我的网络配置: <urlCompression doStaticCompression="false" doDynamicCompression="true" dynamicCompressionBeforeCache="false" />

    在IIS管理器的服务器节点中

    • ,双击 Modules 图标,然后在右侧单击"view ordered List"并验证您的静态/动态压缩模块是否位于顶部,URL重写模块位于底部

    Please Note

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

  • 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

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

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

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

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

相关问题