我正在尝试为我压缩的文件as advised earlier添加Vary: Accept-Encoding
标头。
但是,由于某种原因,无法从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是我上面提供的代码摘录所属的类。)
为什么我无法添加Vary
标题?
编辑: Eric C的解决方案给我留下了这样的代码:
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, CompressionMode.Compress);
app.Response.AppendHeader("Content-Encoding", "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
(不知道为什么这是application/x-javascript
在HTML中设置为text/javascript
,但这是无关紧要的。)
正如您所看到的,我现在有一个不同的标头,但它设置为Vary=*
而不是Vary=Accept-Encoding
,正如您对压缩模块中的代码所期望的那样。
这里发生了什么?如何正确设置Vary
标题?
第二次修改: 我要粘贴整个类的源代码。它没有比我已经发布的更多,但它可能有助于准确掌握我正在做的事情:
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, CompressionMode.Compress);
app.Response.AppendHeader("Content-Encoding", "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>
没有更多要说的了。我所知道的,没有其他非标准的东西我们正在使用该网站。有什么想法吗?
答案 0 :(得分:10)
从IIS 7.5开始,Vary标头被gzip IIS过滤器(gzip.dll)覆盖,该过滤器实现了DyanamicCompressionModule。无论ASP.NET代码中的更改如何,过滤器始终将标头设置为“Vary:Accept-Encoding”。截至今天,唯一的解决方法是禁用动态内容的压缩,然后在代码中实现它。方法如下:
从Web.config中删除以下行:
<add name="CompressionModule" type="Utility.HttpCompressionModule"/>
然后转到IIS管理控制台并确保未对动态内容启用压缩。
在Global.asax.cs
中手动实施压缩,方法HttpApplication.Application_BeginRequest
:
protected void Application_BeginRequest(object sender, EventArgs e) { HttpContext context = HttpContext.Current; context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress); context.Response.AppendHeader("Content-Encoding", "gzip"); context.Response.Cache.VaryByHeaders["Accept-Encoding"] = true; // We can now set additional Vary headers... context.Response.Cache.VaryByHeaders.UserAgent = true; context.Response.Cache.VaryByHeaders["X-Requested-With"] = true; }
这是最近reported to Microsoft的问题。
答案 1 :(得分:4)
尝试:
Response.Cache.SetVaryByCustom("Accept-Encoding");
Response.Cache.SetOmitVaryStar(true);
因为在上面看来某些东西已经使代码确信*在这里是合适的,并且你确定它不是。
请注意,使用IE时,缓存机制存在一个缺陷(部分修复,IIRC与IE9但之前没有),它需要这样一个变化的标头来表示完全无法缓存(这是有效的,但次优的行为)。出于这个原因,有些人更喜欢因User-Agent而异,因为Accept-Encoding是技术上正确的发送值:
注意:您还必须确保使用不同版本(g-zipped,deflated和uncompressed)发送不同的E-Tags作为E-Tags标签实体(发送的字节串,包括任何内容编码但不包括任何传输编码而不是资源,并且不改变电子标签可能会导致您设置Vary: Accept-Encoding
以避免使用相同类型的SNAFU。
如果你不能改变电子标签,那么最好省略它并单独使用最后修改的条件GET。
顺便提一下,您对设置application / x-javascript的原因感到疑惑的答案是,这是服务器与“.js”关联的内容类型。 HTML中的提示不会影响它,因为它不是服务器对此请求所看到的内容,尽管可以用于覆盖内容类型,如果出现像text / plain这样的虚假内容由服务器发送(标准不清楚,用户代理行为可能会有所不同,同时保持在标准的字母内)。由于浏览器通常都认为应用程序/ javascript应用程序/ x-javascript和text / javascript意味着javascript,因此这里很重要。
答案 2 :(得分:2)
试试这个:
app.Response.Cache.SetVaryByCustom("Accept-Encoding");
答案 3 :(得分:2)
您需要手动添加标头值才能看到Vary: Accept-Encoding
。
response.Cache.SetOmitVaryStar(true);
response.AddHeader("Vary", "Accept-Encoding");
答案 4 :(得分:1)
我也试过这些
Response.Cache.SetOmitVaryStar(true);
Response.AddHeader("Vary", "Accept-Encoding");
,但是不行。但是,这确实有效:
Response.Cache.VaryByHeaders["Accept-Encoding"] = true;
答案 5 :(得分:1)
正如其他人所提到的,这是一个known issue,其中IIS压缩模块专门覆盖了Vary
标头,并由hotfix解决。
如果您无法确保安装了此修补程序,则另一种解决方法是在Web.config中使用IIS URL Rewrite附加标头:
<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>