Json HTTP-Compression With Gzip In IIS8

2019-05-02 23:32发布

问题:

Ok, I've been reading for hours about this. Dozens of SO posts and blogs, etc. No answer to be found.

Goal: enable dynamic http compression of json response from my WCF service.

Note: gzip already works for static content and for dynamic content when applicationhost.config contains the following:

<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
            <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" />
        <dynamicTypes>
            <add mimeType="text/*" enabled="true" />
            <add mimeType="message/*" enabled="true" />
            <add mimeType="application/x-javascript" enabled="true" />
            <add mimeType="application/json; charset=utf-8" enabled="true" />
            <add mimeType="*/*" enabled="false" />
        </dynamicTypes>
        <staticTypes>
            <add mimeType="text/*" enabled="true" />
            <add mimeType="message/*" enabled="true" />
            <add mimeType="application/x-javascript" enabled="true" />
            <add mimeType="application/atom+xml" enabled="true" />
            <add mimeType="application/xaml+xml" enabled="true" />
            <add mimeType="*/*" enabled="false" />
        </staticTypes>    
</httpCompression>
</system.webServer>

Unfortunately on the server I'm using the following line is missing from applicationhost.config:

<add mimeType="application/json; charset=utf-8" enabled="true" />

And I cannot add it manually because the server is an AWS EC2 instance launched by Elastic Beanstalk (as such I could change it on one instance but not on all instances whenever they are launched).

Also unfortunately, the applicationhost.config includes this line:

<section name="httpCompression" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />

Which means that I cannot override the httpCompression section in my app's web.config.

My question: are there other approaches to enabling gzip compression of dynamic content that I should try?

If overrideModeDefault="Allow" would I then be able to place the httpCompression section in my app's web.config and expect it to override?

Happy to add further clarification if needed.

Cheers

回答1:

Late to the party here, but this is definitely possible without an AMI.

Create an s3 bucket to host your setup file(s). In this example I have a bucket called mys3bucket. Upload the following file to the bucket under mybucket/ebExtensions/setup.ps1

This file modified the root application host config.

write-host "Applying IIS configuration ..."

$globalConfig = "C:\Windows\System32\inetsrv\config\applicationHost.config"

$xmlDoc = new-object System.Xml.XmlDocument

$xmlDoc.Load($globalConfig)

#Set minimum compression size
write-host "Setting minimum compression size ..."
$xmlCurrentNode = $xmlDoc.SelectSingleNode("/configuration/system.webServer/httpCompression")
if ($xmlCurrentNode -eq $null)
{
    $xmlCurrentNode = $xmlDoc.CreateElement("httpCompression")
    $xmlDoc.SelectSingleNode("/configuration/system.webServer").AppendChild($xmlCurrentNode)
}
$xmlCurrentNode.SetAttribute("minFileSizeForComp", "10240")
$xmlCurrentNode.SetAttribute("dynamicCompressionEnableCpuUsage", "70")
write-host "Done."

#Enable dynamic compression
write-host "Enabling dynamic compression ..."
$xmlCurrentNode = $xmlDoc.SelectSingleNode("/configuration/system.webServer/urlCompression")
if ($xmlCurrentNode -eq $null)
{
    $xmlCurrentNode = $xmlDoc.CreateElement("urlCompression")
    $xmlDoc.SelectSingleNode("/configuration/system.webServer").AppendChild($xmlCurrentNode)
}
$xmlCurrentNode.SetAttribute("doDynamicCompression", "true")
write-host "Done."

#Add dynamic types for compression
write-host "Adding dynamic types ..."
$xmlCurrentNode = $xmlDoc.SelectSingleNode("/configuration/system.webServer/httpCompression/dynamicTypes")
if ($xmlCurrentNode -eq $null)
{
    $xmlCurrentNode = $xmlDoc.CreateElement("dynamicTypes")
    $xmlDoc.SelectSingleNode("/configuration/system.webServer/httpCompression").AppendChild($xmlCurrentNode)
}
$xmlCurrentNode = $xmlDoc.SelectSingleNode("/configuration/system.webServer/httpCompression/dynamicTypes/add[@mimeType='application/*']")
if ($xmlCurrentNode -eq $null)
{
    $xmlCurrentNode = $xmlDoc.CreateElement("add")
    $xmlCurrentNode.SetAttribute("mimeType", "application/*")
    $xmlDoc.SelectSingleNode("/configuration/system.webServer/httpCompression/dynamicTypes").AppendChild($xmlCurrentNode)
}
$xmlCurrentNode.SetAttribute("enabled", "true")
write-host "Done."

write-host "Saving the target config file ..."
$xmlDoc.Save("$globalConfig")
write-host "Done."

Next you need to use elastic beanstalk extensions in your project.

Add the following init.config file to the .ebextensions folder off the root of your web site. This is a YAML file so use space indentation not tabs.

files:
  "c:/cfn/init.ps1":
    content: |
      $instanceDoc = Invoke-RestMethod 'http://169.254.169.254/latest/dynamic/instance-identity/document'
      $extPath = "c:\cfn\.ebextensions"
        if (Test-Path $extPath) {
          Remove-Item $extPath -Recurse
        }
      Read-S3Object -BucketName "mys3bucket" -Folder $extPath -KeyPrefix '/ebExtensions' -Region ($instanceDoc.region)
      . (Join-Path $extPath -ChildPath '\setup.ps1')
container_commands:
  00-invoke-init:
    command: powershell.exe -nologo -noprofile -file "c:\cfn\init.ps1"

Make sure your instance has permission to the bucket via a role, otherwise pass aws credentials in the call to Read-S3Object

The above performs the following

  • On the Files elastic beanstalk event a new file called init.ps1 will be written to c:\cfn\init.ps1
  • During the Commands event the init.ps1 file is executed.
  • The init.ps1 file downloads the setup file from S3 and executes it. (Note you could put all the powershell inline but this keeps the YAML clean and makes it easier to use multiple files during setup going forward.)