如何在Windows Azure上启用gzip HTTP压缩动态内容

58

我一直在尝试在我的 Windows Azure 托管的 WCF Restful 服务上启用 gzip HTTP 压缩,该服务仅从 GET 和 POST 请求返回 JSON,但一直未成功。

我尝试了很多方法,但难以列出它们,我现在意识到我一直在使用冲突的信息(关于旧版本的 azure 等),所以认为最好从干净的状态开始!

我正在使用 Visual Studio 2008,并使用 Visual Studio 的 2010 年 2 月工具。

因此,根据以下 链接..

..HTTP 压缩现在已启用。 我使用了以下页面上的建议(仅使用 URL 压缩建议)..

http://blog.smarx.com/posts/iis-compression-in-windows-azure

<urlCompression doStaticCompression="true" 
         doDynamicCompression="true"
         dynamicCompressionBeforeCache="true" 
/>

但我无法获得压缩。我不知道urlCompressionhttpCompression之间的区别,这并没有帮助我。我试图找出区别,但没有结果!

可能是因为 Visual Studio 的工具在支持压缩的 Azure 版本之前发布,这是一个问题吗?我在某个地方读到,使用最新的工具时,可以选择发布时要使用的 Azure 操作系统版本......但我不知道是否属实,如果是,我找不到选择的位置。我使用的是启用http之前的版本吗?

我还尝试过 blowery http 压缩模块,但没有任何效果。

有人有关于如何实现这一点的最新建议吗?即与当前版本的 Azure 操作系统相关的建议。

谢谢!

史蒂文

更新:我编辑了上面的代码以修复 web.config 片段中的错误。

更新2:使用下面答案中显示的 whatsmyip URL 测试响应时,显示我的 service.svc 的 JSON 响应未经任何压缩返回,但静态HTML页面被gzip压缩返回的。如何使JSON响应压缩的任何建议将不胜感激!

更新3:尝试使用大于256KB的JSON响应,以查看问题是否由于JSON响应小于此值而引起,如下面的评论所述。不幸的是,响应仍未被压缩。


共享主机默认应启用gzip,以支持所有JSON Web服务。虽然这会在服务器上增加一些CPU负载,但我认为通过网络传输更小的数据包所带来的好处远远超过成本。并非所有人都能够使用光纤网络。 - goku_da_master
6个回答

74

花了非常长的时间……但我终于解决了这个问题,我想为任何遇到相同问题的人发布答案。解决方案非常简单,我已经验证过一定可以工作!

编辑你的ServiceDefinition.csdef文件,在WebRole标签中添加以下内容:

    <Startup>
      <Task commandLine="EnableCompression.cmd" executionContext="elevated" taskType="simple"></Task>
    </Startup>

在您的 Web 角色中,创建一个文本文件并将其保存为 "EnableCompression.cmd"。

"EnableCompression.cmd" 应包含以下内容:

%windir%\system32\inetsrv\appcmd set config /section:urlCompression /doDynamicCompression:True /commit:apphost
%windir%\system32\inetsrv\appcmd set config  -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='application/json; charset=utf-8',enabled='True']" /commit:apphost

就是这样!完成了!这使得Web角色返回的JSON启用了动态压缩,我记得在某个地方看到过它具有相当奇怪的MIME类型,所以请确保你完全复制了代码。


1
不用管了,在这里找到答案了(需要 SDK 1.5)http://blog.smarx.com/posts/skipping-windows-azure-startup-tasks-when-running-in-the-emulator - Oliver Weichhold
您将Startup Task的taskType设置为taskType="simple",脚本是否必须在simple模式下运行,还是也可以使用background模式?(有关差异的澄清,请参见此处) - Luke Merrett
@Steven,你知道我们怎样可以从Azure压缩图片吗? - mmssaann
这仍然是首选的方法吗?我不禁觉得在部署时运行批处理文件是一种hack。我找到了这篇文章https://azure.microsoft.com/en-us/blog/more-to-explore-configuration-options-unlocked-in-windows-azure-web-sites/,但目前还不确定如何实现它。 - The Senator
据我所知,他们似乎没有为云服务添加更方便的功能(在Azure中,云服务几乎已经不再是托管选项,并且多年来一直没有任何改进)。另外请注意@TheSenator的链接谈论的是Azure网站,而不是Azure云服务。 - Mike Asdf
显示剩余3条评论

13

至少我不是唯一一个遇到这个问题的人,而且这个问题仍然让人非常烦恼,已经快一年了。

问题出在MIME类型不匹配上。WCF返回带有 Content-Type: application/json; charset=UTF-8 的JSON响应。但是默认的IIS配置中并没有将其包含在可压缩的MIME类型中。

现在,你可能会想要在web.config中添加一个<httpCompression>部分,并将application/json添加进去。但是这只是浪费时间的办法,因为你只能在applicationHost.config级别更改<httpCompression>元素。

所以有两种可能的解决方案。首先,你可以将WCF响应更改为使用在默认配置中可压缩的MIME类型。例如,text/json 将起作用,所以在你的服务方法中添加这个内容将给你动态压缩:WebOperationContext.Current.OutgoingResponse.ContentType = "text/json";

另外,你可以使用appcmd和启动任务更改applicationHost.config文件。这在这个帖子中讨论过(以及其他内容)。请注意,如果你添加了该启动任务并在开发环境中运行它,则只会运行一次。第二次将失败,因为你已经添加了配置元素。我最终创建了一个具有单独的csdef文件的第二个云项目,让我的devfabric不运行该启动脚本。但是可能还有其他解决方案。

更新

我之前提到的将项目分开的建议并不是一个好主意。非幂等的启动任务是一个非常糟糕的想法,因为某一天Azure平台会决定代替你重新启动实例,这时启动任务就会失败,并进入循环回收阶段。很可能是在深夜发生。相反地,请根据此SO讨论中所述,确保您的启动任务是幂等的。


值得注意的是,<httpCompression> 必须添加到 applicationHost.config 级别。我敢打赌许多人 - 包括我自己在内 - 曾经浪费了时间尝试通过修改 web.config 来使其工作。 - pberggreen

4
为了解决第一次部署后本地开发环境出现问题,我在CMD文件中添加了适当的命令来重置配置。此外,我在这里特别设置了压缩级别,因为在某些情况下它似乎默认为零。
REM Remove old settings - keeps local deploys working (since you get errors otherwise)
%windir%\system32\inetsrv\appcmd reset config -section:urlCompression
%windir%\system32\inetsrv\appcmd reset config -section:system.webServer/httpCompression 

REM urlCompression - is this needed?
%windir%\system32\inetsrv\appcmd set config -section:urlCompression /doDynamicCompression:True /commit:apphost
REM Enable json mime type
%windir%\system32\inetsrv\appcmd set config -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='application/json; charset=utf-8',enabled='True']" /commit:apphost

REM IIS Defaults
%windir%\system32\inetsrv\appcmd set config -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='text/*',enabled='True']" /commit:apphost
%windir%\system32\inetsrv\appcmd set config -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='message/*',enabled='True']" /commit:apphost
%windir%\system32\inetsrv\appcmd set config -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='application/x-javascript',enabled='True']" /commit:apphost
%windir%\system32\inetsrv\appcmd set config -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='*/*',enabled='False']" /commit:apphost
%windir%\system32\inetsrv\appcmd set config -section:system.webServer/httpCompression /+"staticTypes.[mimeType='text/*',enabled='True']" /commit:apphost
%windir%\system32\inetsrv\appcmd set config -section:system.webServer/httpCompression /+"staticTypes.[mimeType='message/*',enabled='True']" /commit:apphost
%windir%\system32\inetsrv\appcmd set config -section:system.webServer/httpCompression /+"staticTypes.[mimeType='application/javascript',enabled='True']" /commit:apphost
%windir%\system32\inetsrv\appcmd set config -section:system.webServer/httpCompression /+"staticTypes.[mimeType='*/*',enabled='False']" /commit:apphost

REM Set dynamic compression level to appropriate level.  Note gzip will already be present because of reset above, but compression level will be zero after reset.
%windir%\system32\inetsrv\appcmd.exe set config -section:system.webServer/httpCompression /+"[name='deflate',doStaticCompression='True',doDynamicCompression='True',dynamicCompressionLevel='7',dll='%%Windir%%\system32\inetsrv\gzip.dll']" /commit:apphost
%windir%\system32\inetsrv\appcmd.exe set config -section:system.webServer/httpCompression -[name='gzip'].dynamicCompressionLevel:7 /commit:apphost

3

我刚遇到了一个关于错误类型183的问题,但是我找到了解决方法。如果其他人也遇到这个问题,可以看一下以下内容:

这是我收到的错误提示:

用户程序“F:\approot\bin\EnableCompression.cmd”以非零退出代码183退出。 工作目录为F:\approot\bin。

下面的代码为我解决了这个问题:

REM   *** Add a compression section to the Web.config file. ***
%windir%\system32\inetsrv\appcmd set config /section:urlCompression /doDynamicCompression:True /commit:apphost >> "%TEMP%\StartupLog.txt" 2>&1

REM   ERRORLEVEL 183 occurs when trying to add a section that already exists. This error is expected if this
REM   batch file were executed twice. This can occur and must be accounted for in a Windows Azure startup
REM   task. To handle this situation, set the ERRORLEVEL to zero by using the Verify command. The Verify
REM   command will safely set the ERRORLEVEL to zero.
IF %ERRORLEVEL% EQU 183 DO VERIFY > NUL

REM   If the ERRORLEVEL is not zero at this point, some other error occurred.
IF %ERRORLEVEL% NEQ 0 (
   ECHO Error adding a compression section to the Web.config file. >> "%TEMP%\StartupLog.txt" 2>&1
   GOTO ErrorExit
)

REM   *** Add compression for json. ***
%windir%\system32\inetsrv\appcmd set config  -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='application/json; charset=utf-8',enabled='True']" /commit:apphost >> "%TEMP%\StartupLog.txt" 2>&1
IF %ERRORLEVEL% EQU 183 VERIFY > NUL
IF %ERRORLEVEL% NEQ 0 (
   ECHO Error adding the JSON compression type to the Web.config file. >> "%TEMP%\StartupLog.txt" 2>&1
   GOTO ErrorExit
)

REM   *** Exit batch file. ***
EXIT /b 0

REM   *** Log error and exit ***
:ErrorExit
REM   Report the date, time, and ERRORLEVEL of the error.
DATE /T >> "%TEMP%\StartupLog.txt" 2>&1
TIME /T >> "%TEMP%\StartupLog.txt" 2>&1
ECHO An error occurred during startup. ERRORLEVEL = %ERRORLEVEL% >> "%TEMP%\StartupLog.txt" 2>&1
EXIT %ERRORLEVEL%

解决方案可在http://msdn.microsoft.com/en-us/library/azure/hh974418.aspx找到。


3

0

是的,您可以选择您想要的操作系统,但默认情况下,您将获得最新版本。

压缩是棘手的。有很多事情可能会出错。您是否碰巧在代理服务器后面进行此测试?我相信IIS默认不会向代理发送压缩内容。当我在尝试这个功能时,我找到了一个方便的工具来测试压缩是否有效:http://www.whatsmyip.org/http_compression/

看起来您设置了doDynamicCompression="false" ...那只是一个打字错误吗?如果您要从Web服务返回的JSON上获得压缩效果,则需要打开该选项。


嗨!感谢您的快速回复!那是一个打字错误,该行应该是:我使用了您建议的whatsmyip URL进行了一些测试。我的JSON响应(来自我的service.svc)没有任何压缩,但静态HTML页面正在被压缩。您有任何建议我从这里可以去哪里吗?再次感谢 - Steven Elliott
尝试生成非常大的JSON。根据http://msdn.microsoft.com/en-us/library/ms690689(VS.90).aspx, 默认的minSize设置为256 KB。 - user94559
我创建了一个大小为280KB的虚假响应,并在whatsmyip上进行了测试...不幸的是它仍然未被压缩。 - Steven Elliott
我很确定你可以通过创建自定义的IHTTPModule(http://www.west-wind.com/weblog/posts/2007/Jan/23/Building-a-GZip-JavaScript-Resource-Compression-Module-for-ASPNET),并将其添加到Azure(http://blogs.msdn.com/b/tom/archive/2011/02/18/installing-and-using-an-httpmodule-in-windows-azure.aspx)来启用GZIP压缩。 - user152949

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