我正在尝试添加一个Vary:Accept-Encoding头到对我压缩的文件的响应,as advised earlier.
但是,由于某些原因,这是不可能的 – 无论是从Visual Studio测试服务器还是IIS服务器.
我有以下代码:
if (url.Contains(".js") || url.Contains(".aspx") || url.Contains(".css")) { app.Response.AppendHeader("Vary","Accept-Encoding"); app.Response.AppendHeader("Varye","Accept-Encoding"); // for testing app.Response.AppendHeader("Varye","Accept-Things"); // for testing app.Response.AppendHeader("Vary","Accept-Stuff"); // for testing app.Response.AppendHeader("Var","Accept-Items"); // for testing encodings = encodings.ToLower(); if (encodings.Contains("gzip") || encodings == "*") { app.Response.Filter = new GZipStream(baseStream,CompressionMode.Compress); app.Response.AppendHeader("Content-Encoding","gzip"); } }
这导致以下响应标题:
Status=OK - 200 Server=ASP.NET Development Server/10.0.0.0 Date=Fri,21 Oct 2011 12:24:11 GMT X-AspNet-Version=4.0.30319 Varye=Accept-Encoding,Accept-Things Var=Accept-Items Content-Encoding=gzip Cache-Control=public Etag="1CC8F2E9D772300" Content-Type=text/css Content-Length=16200 Connection=Close
您可以看到,Vary标题不存在.存在具有相似语法的无意义的头文件,因此在发送之前必须有某些东西取出Vary标题.
我不知道它是否相关,但这里是我在web.config中定义我的压缩模块的地方:
<httpModules> <add name="CompressionModule" type="Utility.HttpCompressionModule"/> </httpModules>
(其中Utility.HttpCompressionModule是我上面提供的代码摘录所属的类.)
if (url.Contains(".js") || url.Contains(".aspx") || url.Contains(".css")) { app.Response.Cache.SetVaryByCustom("Accept-Encoding"); encodings = encodings.ToLower(); if (encodings.Contains("gzip") || encodings == "*") { app.Response.Filter = new GZipStream(baseStream,"gzip"); }
但是,标题看起来像这样:
Status=OK - 200 Server=ASP.NET Development Server/10.0.0.0 Date=Mon,24 Oct 2011 09:26:37 GMT Content-Encoding=gzip Cache-Control=public Etag="1CC7A09FDE77300" Vary=* Content-Type=application/x-javascript Content-Length=44447 Connection=Close
(不知道为什么这是应用程序/ x-javascript作为其在HTML中设置为text / javascript,但这是无关紧要的.)
正如你所看到的,我现在有一个不同的标题,但是它被设置为Vary = *而不是Vary = Accept-Encoding,正如您从压缩模块中的代码所期望的那样.
第二编辑:
我要粘贴整个类的源代码.没有比我已经发布的更多,但它可能有助于掌握正在做什么:
public class HttpCompressionModule : IHttpModule { /// <summary> /// Initializes a new instance of the <see cref="AjaxHttpCompressionModule"/> class. /// </summary> public HttpCompressionModule() { } #region IHttpModule Members /// <summary> /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>. /// </summary> void IHttpModule.Dispose() { } /// <summary> /// Initializes a module and prepares it to handle requests. /// </summary> /// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods,properties,and events common to all application objects within an ASP.NET application</param> void IHttpModule.Init(HttpApplication context) { context.BeginRequest += (new EventHandler(this.context_BeginRequest)); } #endregion /// <summary> /// Handles the BeginRequest event of the context control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> void context_BeginRequest(object sender,EventArgs e) { HttpApplication app = (HttpApplication)sender; string encodings = app.Request.Headers.Get("Accept-Encoding"); Stream baseStream = app.Response.Filter; if (string.IsNullOrEmpty(encodings)) return; string url = app.Request.RawUrl.ToLower(); if (url.Contains(".js") || url.Contains(".css") || url.Contains("ajax.ashx")) { app.Response.Cache.SetVaryByCustom("Accept-Encoding"); encodings = encodings.ToLower(); if (encodings.Contains("gzip") || encodings == "*") { app.Response.Filter = new GZipStream(baseStream,CompressionMode.Compress); app.Response.AppendHeader("Content-Encoding","gzip"); } else if (encodings.Contains("deflate")) { app.Response.Filter = new DeflateStream(baseStream,"deflate"); } } } }
此外,这是我的web.config文件的System.Web部分:
<system.web> <!--<compilation debug="true"></compilation>--> <trace enabled="true" traceMode="SortByTime"/> <httpRuntime executionTimeout="180"/> <globalization culture="en-GB" uiCulture="en-GB"/> <!-- custom errors--> <customErrors mode="Off"> </customErrors> <!-- Membership --> <membership defaultProvider="sqlProvider" userIsOnlineTimeWindow="15"> <providers> <clear/> <add name="sqlProvider" type="System.Web.Security.sqlMembershipProvider" connectionStringName="sqlServerAuth" applicationName="mycompany" minrequiredPasswordLength="4" minrequiredNonalphanumericCharacters="0" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" passwordFormat="Hashed" maxInvalidPasswordAttempts="1024"/> </providers> </membership> <!-- Roles --> <roleManager enabled="true" cacheRolesInCookie="true" defaultProvider="sqlProvider"> <providers> <clear/> <add connectionStringName="sqlServerAuth" applicationName="mycompany" name="sqlProvider" type="System.Web.Security.sqlRoleProvider"/> </providers> </roleManager> <!-- Authentication --> <anonymousIdentification enabled="false"/> <authentication mode="Forms"> <forms name=".AUTH" protection="All" timeout="2" path="/"> </forms> </authentication> <httpModules> <add name="CompressionModule" type="Utility.HttpCompressionModule"/> </httpModules> </system.web>
没有什么可说的.我所了解的这个网站没有其他非标准的东西.有任何想法吗?
解决方法
如其他人所说,这是一个
known issue,IIS压缩模块专门覆盖Vary头,并已在
hotfix处理.
如果您无法确保该修补程序已安装,另一个解决方法是使用IIS URL Rewrite在Web.config中附加标题:
<configuration> <system.webServer> <rewrite> <outboundRules> <rule name="Append 'Vary: X-Requested-With' header" patternSyntax="ECMAScript"> <match serverVariable="RESPONSE_VARY" pattern=".+" /> <action type="Rewrite" value="{R:0},X-Requested-With" replace="true" /> </rule> <rule name="Set 'Vary: X-Requested-With' header if no others" patternSyntax="ECMAScript"> <match serverVariable="RESPONSE_VARY" pattern=".+" negate="true" /> <action type="Rewrite" value="X-Requested-With" /> </rule> </outboundRules> </rewrite> </system.webServer> </configuration>