GZipStream 正在切断 XML 的最后一部分

发布于 2024-09-18 03:11:22 字数 914 浏览 6 评论 0原文

我创建了一个名为 AddGZip 的扩展方法,如下所示:

public static void AddGZip(this HttpResponse response)
{
    response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
    response.AppendHeader("Content-Encoding", "gzip");
}

这是代码的精简版本:

var response = HttpContext.Current.Response;
var request = HttpContext.Current.Request;
var result = File.ReadAllText(path);
if (request.SupportsGZip)
{
  response.AddGZip();
}
response.Write(result);
response.Flush();

当您在支持 GZip 的 Web 浏览器中查看响应时,您会收到如下错误:

“XML 解析错误:未封闭的令牌 位置:http://webserver1/1234.xml 第 78 行,第 1 列:"

当我查看源代码时,它基本上错过了 XML 文件末尾的最后一个 >。所以 1 或 2 个字节。

如果我注释掉 AddGZip 行,它工作正常,但是我真的很想支持 GZip,因为 XML 可能非常大。

了很多博客,但似乎没有针对此类错误的解决方案。

我已经尝试检查

I have created an extension method called AddGZip which looks like the following:

public static void AddGZip(this HttpResponse response)
{
    response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
    response.AppendHeader("Content-Encoding", "gzip");
}

This is a very cut down version of the code:

var response = HttpContext.Current.Response;
var request = HttpContext.Current.Request;
var result = File.ReadAllText(path);
if (request.SupportsGZip)
{
  response.AddGZip();
}
response.Write(result);
response.Flush();

When you view the response in a web browser with GZip support you get an error like this:

"XML Parsing Error: unclosed token
Location: http://webserver1/1234.xml
Line Number 78, Column 1:"

When i view the source it's basically missed out the last > from the end of the XML file. So 1 or 2 bytes.

If I comment out the AddGZip Line it works fine. However I really want to support GZip as the XML can be quite large.

Does anyone have a suggestion for me? I've tried checking lots of blogs but no solution seems to be out there for this type of error.

Dave

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

随遇而安 2024-09-25 03:11:34

您是否尝试过通过 IIS 添加 gzip?有一个关于它的问题,所以看看它是关于什么的。基本上,IIS 会完成所有压缩工作,因此您无需这样做。

Have you tried adding gzip through IIS? There is a question about it, so have a look what's it about. Basically, the IIS does all the compression so you don't have to.

七婞 2024-09-25 03:11:32

DeflateStreamGZipStream 构建于 DeflateStream 之上并继承了问题*),刷新可能会丢失数据。

Response.Flush() 将刷新过滤器。解决方案是使用一个能够识别压缩和底层接收器的包装器,并且仅刷新后者:

public enum CompressionType
{
    Deflate,
    GZip
}
/// <summary>
/// Provides GZip or Deflate compression, with further handling for the fact that
/// .NETs GZip and Deflate filters don't play nicely with chunked encoding (when
/// Response.Flush() is called or buffering is off.
/// </summary>
public class WebCompressionFilter : Stream
{
    private Stream _compSink;
    private 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;
        }
    }
    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);
    }
}

还值得注意的是,大多数支持 gzip 编码的用户代理也支持 deflate 编码。虽然 deflate 的大小改进可以忽略不计(实际上是几个字节),但某些架构上的某些库可以更好地处理 deflate(这适用于压缩和解压缩),因此在 HTTP 压缩中,与 gzip 相比,deflate 总是值得支持的。

There is an issue (or perhaps a really clever feature that I haven't seen justified anywhere) with DeflateStream (GZipStream builds on DeflateStream and inherits the issue*), where flushing can lose data.

Response.Flush() will flush the filter. The solution is to use a wrapper that is aware of both the zipping and the underlying sink, and only flushes the latter:

public enum CompressionType
{
    Deflate,
    GZip
}
/// <summary>
/// Provides GZip or Deflate compression, with further handling for the fact that
/// .NETs GZip and Deflate filters don't play nicely with chunked encoding (when
/// Response.Flush() is called or buffering is off.
/// </summary>
public class WebCompressionFilter : Stream
{
    private Stream _compSink;
    private 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;
        }
    }
    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);
    }
}

It's also worth noting that most user-agents that support gzip-encoding also support deflate-encoding. While the size improvement with deflate is negliable (literally a few bytes), some libraries on some architecture deals with deflate considerably better (this goes for both compressing and decompressing), so it's always worth favouring deflate over gzip with HTTP compression.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文