Setup IIS10 to serve pre-compressed files

梦想的初衷 提交于 2019-12-02 03:24:23

A more neat and elegant solution:

NOTICE: The file extension .gzip seems strange, in general, we name a gziped file as .gz, so in this example, we use .gz instead .gzip, if you insist on .gzip, just replace all the extensions in the following config file.


Code first, this is what all we need for 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>

And, here are how it works:

In order to achieve a successful gziped data transmission, we need:

  • Client side accept gziped data, Accept-Encoding
  • Response with a header with Content-Encoding
  • Proper MIME type, as the original file is, BUT NOT application/gzip
  • Gziped file

The four conditions must be satisfied at the same time.

If you send an uncompressed file with Content-Encoding: gzip, the browser will return an error;

If you send a compressed file without a Content-Encoding header, or a mismatched MIME type, the page may return some Zenith Star's text.

So what we are doing is:

  • Redefine each type of gziped file's MIME
  • If the client side accept a gziped file, then redirect the response file to a gziped version on the server side directly (not 302/303/307 response)
  • Rewrite the header of the response header of Content-Encoding, only if the client side send the header Accept-Encoding

This solution works on my IIS7, not sure if it will also work on IIS10.

If you met any problem, let me know :D

After a long time searching I found a workaround with URL-Rewrite.

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

It's successfull handels BR and GZIP requests for pre-build angular files (JS, CSS, SVG).

I hope this helps someone else. If you know a better solution let me know.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!