Nic*_*ray 6 compression asp.net-mvc firefox
在ASP.Net MVC 2中我使用以下压缩过滤器,在Chrome中它工作正常,但在Firefox 3.3.6中它返回奇怪的字符.
public class CompressAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//get request and response
var request = filterContext.HttpContext.Request;
var response = filterContext.HttpContext.Response;
//get requested encoding
if (!string.IsNullOrEmpty(request.Headers["Accept-Encoding"]))
{
string enc = request.Headers["Accept-Encoding"].ToUpperInvariant();
//preferred: gzip or wildcard
if (enc.Contains("GZIP") || enc.Contains("*"))
{
response.AppendHeader("Content-encoding", "gzip");
response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
}
//deflate
else if (enc.Contains("DEFLATE"))
{
response.AppendHeader("Content-encoding", "deflate");
response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
}
}
base.OnActionExecuting(filterContext);
}
}
Run Code Online (Sandbox Code Playgroud)
以下是Firefox显示的字符示例:
I?%&/m?{J?J??t??$ @ iG#)* eVe] f @ 흼 { { ; N' ?\fdl Jɞ!?
原因是什么?
我发现的一些事情导致滚动自己的压缩问题.
第一.某些情况导致完全更改响应的处理方式(Server.Transfer,一个HTTP模块延迟到另一个HTTP模块)可能会清除标头,但保留流.Fiddler会很快告诉你是否是这种情况.一种可能性是,当您转到错误响应时会发生这种情况,并且在FF情况下发生错误.自己强制解压缩流应该有助于诊断.
相反,一系列事件可能导致标题和/或压缩加倍,因此您最终会发送一个gzip和类似的gzip.更糟糕的是,过滤器可能已在响应中途进行了部分更改.
第三.只是放入DeflateStream或GZipStream作为过滤器不能正确处理使用分块编码的情况(缓冲关闭,调用HttpResponse.Flush(),或者发送大于允许的最大缓冲区大小的响应).下面的流类正确地处理了这种情况(它的重写是Flush()修复,我发现在处理上述情况时有用的额外公共属性).
public enum CompressionType
{
Deflate,
GZip
}
public sealed class WebCompressionFilter : Stream
{
private readonly Stream _compSink;
private readonly Stream _finalSink;
public WebCompressionFilter(Stream stm, CompressionType comp)
{
switch(comp)
{
case CompressionType.Deflate:
_compSink = new DeflateStream((_finalSink = stm), CompressionMode.Compress);
break;
case CompressionType.GZip:
_compSink = new GZipStream((_finalSink = stm), CompressionMode.Compress);
break;
default:
throw new ArgumentException();
}
}
public Stream Sink
{
get
{
return _finalSink;
}
}
public CompressionType CompressionType
{
get
{
return _compSink is DeflateStream ? CompressionType.Deflate : CompressionType.GZip;
}
}
public override bool CanRead
{
get
{
return false;
}
}
public override bool CanSeek
{
get
{
return false;
}
}
public override bool CanWrite
{
get
{
return true;
}
}
public override long Length
{
get
{
throw new NotSupportedException();
}
}
public override long Position
{
get
{
throw new NotSupportedException();
}
set
{
throw new NotSupportedException();
}
}
public override void Flush()
{
//We do not flush the compression stream. At best this does nothing, at worse it
//loses a few bytes. We do however flush the underlying stream to send bytes down the
//wire.
_finalSink.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
_compSink.Write(buffer, offset, count);
}
public override void WriteByte(byte value)
{
_compSink.WriteByte(value);
}
public override void Close()
{
_compSink.Close();
_finalSink.Close();
base.Close();
}
protected override void Dispose(bool disposing)
{
if(disposing)
{
_compSink.Dispose();
_finalSink.Dispose();
}
base.Dispose(disposing);
}
}
Run Code Online (Sandbox Code Playgroud)
第四.使用内容编码(而不是传输编码),HTTP认为您实际上发送的是与不同编码不同的实体.(传输编码认为您只是使用编码,因此使用的带宽较少,这是我们通常真正想要的,但是对传输编码的支持并不常见,所以我们通过使用内容编码来改进) .因此你需要确保不同的编码之间的电子标签(如果有的话)是不同的(在最后一个"字符应该做的时候,为gzip添加一个G和默认为D,只是不要重复mod -gzip把它放在"角色"之后的错误.
第五.与此相关,您必须发送适当的Vary标头,因为您可以根据内容编码进行更改.正确执行此操作意味着发送Vary:Accept-Encoding,以指示您发送的内容将取决于该标题的值.因为这会导致IE出现问题(幸好下一版本会有一些改进,根据MS),有些人会发送Vary:User-Agent(基于大多数用户代理要么接受压缩内容编码,要么不接受比有时请求而不是其他人请求.请注意,在准备压缩时需要设置Vary标头,即使在不准备压缩的情况下也是如此.
第六.即使你正在完美地完成所有事情,你开发早期的缓存中的某些东西也会搞乱它,因为你刚刚在缓存后更改了缓存规则.清除缓存.
如果这些都不符合要求,至少要看看你在Fiddler这样的工具中看到的内容,以及如果手动解压缩发送到FF的流,你会看到它,它肯定会有所帮助.
顺便提一下,无论客户偏好如何,上面的代码都支持GZip over Deflate.如果我要忽略客户声明的偏好顺序,我会反过来做.由于GZip是基于Deflate构建的,因此GZip总是略大于Deflate.这种差异是negliable,但更重要的是一些实现将需要多少更多的CPU时间比缩小数据G-ZIP数据进行工作,这取决于架构以及软件(所以只是一台机器上测试并不能告诉你足够判断这是否适用),因此对于在低端机器上运行浏览器的客户端,gzip和deflate之间的明显差异可能不仅仅是下载gzip将发送的几个额外八位字节.
| 归档时间: |
|
| 查看次数: |
1097 次 |
| 最近记录: |