配置IIS10以提供预先压缩的文件。

8
我的angular2项目为我的Web应用程序构建预压缩的gzip文件,但我的IIS只提供普通的“.js”文件,而不是压缩的“.gzip”文件。我的浏览器愿意接受gzip。
那么,允许gzip响应的IIS正确设置是什么?
我已经搜索了Google / SO / SU,但只找到了不适用于“预压缩”内容的解决方案。
2个回答

9

一种更简洁、优雅的解决方案:

注意:文件扩展名 .gzip 看起来有些奇怪,通常我们将一个 gzip 压缩的文件命名为 .gz,因此在本例中,我们使用 .gz 代替 .gzip,如果您坚持使用 .gzip,只需在下面的配置文件中替换所有扩展名即可。


先看代码,这就是我们需要的全部内容:web.config

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <staticContent>
      <remove fileExtension=".js.gz" />
      <remove fileExtension=".css.gz" />
      <remove fileExtension=".png.gz" />
      <remove fileExtension=".jpg.gz" />
      <remove fileExtension=".gif.gz" />
      <remove fileExtension=".svg.gz" />
      <remove fileExtension=".html.gz" />
      <remove fileExtension=".json.gz" />
      <mimeMap fileExtension=".js.gz" mimeType="application/javascript" />
      <mimeMap fileExtension=".css.gz" mimeType="text/css" />
      <mimeMap fileExtension=".png.gz" mimeType="image/png" />
      <mimeMap fileExtension=".jpg.gz" mimeType="image/jpeg" />
      <mimeMap fileExtension=".gif.gz" mimeType="image/gif" />
      <mimeMap fileExtension=".svg.gz" mimeType="image/svg+xml" />
      <mimeMap fileExtension=".html.gz" mimeType="text/html" />
      <mimeMap fileExtension=".json.gz" mimeType="application/json" />
    </staticContent>
  
    <rewrite>
      <outboundRules rewriteBeforeCache="true">
        <rule name="Custom gzip file header">
          <match serverVariable="RESPONSE_CONTENT_ENCODING" pattern=".*" />
          <conditions>
            <add input="{REQUEST_URI}" pattern="\.gz$" />
          </conditions>
          <action type="Rewrite" value="gzip"/>
        </rule>
      </outboundRules>
      
      <rules>
        <rule name="Rewrite gzip file">
          <match url="(.*)"/>
          <conditions>
            <add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" />
            <add input="{REQUEST_FILENAME}.gz" matchType="IsFile" />
          </conditions>
          <action type="Rewrite" url="{R:1}.gz" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

以下是它的工作原理:

为了实现成功的gzip数据传输,我们需要:

  • 客户端接受gzip数据,Accept-Encoding
  • 响应一个带有Content-Encoding头的文件
  • 适当的MIME类型,与原始文件相同,但不是application/gzip
  • gzip文件

这四个条件必须同时满足。

如果您发送一个未压缩的文件,并带有Content-Encoding: gzip,浏览器将返回错误;

如果您发送一个没有Content-Encoding头或MIME类型不匹配的压缩文件,则页面可能会返回一些Zenith Star的文本。

所以我们正在做的是:

  • 重新定义每种gzip文件的MIME类型
  • 如果客户端接受gzip文件,则将响应文件重定向到服务器端的gzip版本(而不是302/303/307响应)
  • 仅在客户端发送头Accept-Encoding时,重写响应标头的Content-Encoding

此解决方案适用于我的IIS7,不确定它是否也适用于IIS10。

如果遇到任何问题,请告诉我:D


感谢您指出这一点。不幸的是,我无法在IIS 10中使其工作(您说可能不行)。此外,我最终发现我们在这里查看的答案https://dev59.com/8FcO5IYBdhLWcg3wzEuf#45397352?noredirect=1#comment85923508_45397352在所有浏览器中都无法正常工作。例如,FireFox将无法加载任何.js文件,并显示错误SyntaxError:非法字符。虽然我无法确认或否认您的解决方案是否存在相同的问题。 - mikeo
@mikeo 嗯嗯嗯,我刚在我的 Windows 10 上尝试了这个配置,使用 IIS 10,它运行得很好... - Losses Don
它提供了预压缩的文件吗?而不是动态压缩的文件?这就是我无法实现的地方。它提供了压缩文件,但它们是动态压缩的文件...显示的文件大小比我预先压缩的文件要大一些。如果是这样的话,我会再试一次并告诉你。 - mikeo
是的,我两次都进行了尝试(在不同的故障排除时间)。当我去掉动态压缩时,它只会提供比预先压缩或动态压缩的文件更大的完整文件。奇怪的是,其他答案的设置(这个设置与您的类似但不那么强大)在IIS10中可以正常工作(除了Firefox),所以我不确定为什么这个不起作用。 - mikeo
此外,您需要在IIS上安装“URL Rewrite”。否则,将引发HTTP错误500.19和HRESULT 0x8007000d。 - Rzassar
显示剩余2条评论

2

经过长时间的搜索,我找到了使用URL重写的解决方法。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <remove name="X-Powered-By" />
            </customHeaders>
        </httpProtocol>
        <rewrite>
            <rules>
                <clear />
                <rule name="Https redirect" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{HTTP_HOST}" pattern="^domain.com$" />
                        <add input="{HTTPS}" pattern="^OFF$" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" />
                </rule>
                <rule name="LetsEncrypt">
                    <match url=".well-known/acme-challenge/*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
                    <action type="None" />
                </rule>
                <rule name="Angular Routes" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                        <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="/" />
                </rule>
                <rule name="br_rewrite" enabled="true" stopProcessing="true">
                    <match url="(.*).(js$|svg|css)" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{HTTP_ACCEPT_ENCODING}" pattern="br" />
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" />
                    </conditions>
                    <action type="Rewrite" url="{R:1}.{R:2}.br" logRewrittenUrl="true" />
                </rule>
                <rule name="gzip_rewrite" enabled="true" stopProcessing="true">
                    <match url="(.*).(js$|svg|css)" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{HTTP_ACCEPT_ENCODING}" pattern="gzip" />
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" />
                    </conditions>
                    <action type="Rewrite" url="{R:1}.{R:2}.gz" logRewrittenUrl="true" />
                </rule>
            </rules>
            <outboundRules rewriteBeforeCache="true">
                <rule name="Remove Server header" enabled="true">
                    <match serverVariable="RESPONSE_Server" pattern=".+" />
                    <action type="Rewrite" value="" />
                </rule>
                <rule name="Rewrite content-encoding header gzip" preCondition="IsGZ" enabled="true" stopProcessing="false">
                    <match serverVariable="RESPONSE_CONTENT_ENCODING" pattern=".*" />
                    <action type="Rewrite" value="gzip" />
                </rule>
                <rule name="Rewrite content-encoding header br" preCondition="IsBR" enabled="true" stopProcessing="false">
                    <match serverVariable="RESPONSE_CONTENT_ENCODING" pattern=".*" />
                    <action type="Rewrite" value="br" />
                </rule>
                <rule name="css content type" preCondition="IsCSS" enabled="true" stopProcessing="false">
                    <match serverVariable="RESPONSE_CONTENT_TYPE" pattern="(.*)" />
                    <action type="Rewrite" value="text/css" />
                </rule>
                <rule name="js content type" preCondition="IsJS" enabled="true" stopProcessing="false">
                    <match serverVariable="RESPONSE_CONTENT_TYPE" pattern="(.*)" />
                    <action type="Rewrite" value="application/javascript" />
                </rule>
                <rule name="svg content type" preCondition="IsSVG" enabled="true" stopProcessing="false">
                    <match serverVariable="RESPONSE_CONTENT_TYPE" pattern="(.*)" />
                    <action type="Rewrite" value="image/svg+xml" />
                </rule>
                <preConditions>
                    <preCondition name="IsGZ">
                        <add input="{URL}" pattern="\.gz$" />
                    </preCondition>
                    <preCondition name="IsBR">
                        <add input="{URL}" pattern="\.br$" />
                    </preCondition>
                    <preCondition name="IsCSS">
                        <add input="{URL}" pattern="css" />
                    </preCondition>
                    <preCondition name="IsJS">
                        <add input="{URL}" pattern="js" />
                    </preCondition>
                    <preCondition name="IsSVG">
                        <add input="{URL}" pattern="svg" />
                    </preCondition>
                </preConditions>
            </outboundRules>
        </rewrite>
        <urlCompression doStaticCompression="true" doDynamicCompression="false" />
        <httpCompression sendCacheHeaders="false" />
        <staticContent>
            <mimeMap fileExtension=".br" mimeType="application/brotli" />
            <clientCache cacheControlMode="UseMaxAge" />
        </staticContent>
    </system.webServer>
</configuration>

它可以成功处理预构建的Angular文件(JS,CSS,SVG)的BR和GZIP请求。

我希望这能帮助其他人。如果您知道更好的解决方案,请告诉我。


使用这种解决方法,我可以看到 Chrome 现在使用 brotli 文件。但是当我移除 brotli 规则并保留 gzip 时,在 IIS 10 中压缩无法正常工作。@Alex - Uthpala Pathirana
我不是IIS的专家,所以我的解决方案是试错(很可能非常容易出错)。你尝试过@Losses Don提供的解决方案吗?他提供了一个更干净的解决方案,如果你只需要gzip,那么可能不会出现问题。 - Alex
我试过了。使用它似乎可以提供gz文件(通过大小我理解了),但由于缺少头部content-encoding: gzip,会出现语法错误,导致浏览器无法解码。 - Uthpala Pathirana
我发现即使服务器已经按照要求配置,仍需要启用SSL才能获取预压缩文件。 - Uthpala Pathirana

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接