4

次のような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 Lineをコメントアウトすると、正常に機能します。ただし、XMLは非常に大きくなる可能性があるため、GZipをサポートしたいと思います。

誰かが私に提案がありますか?私はたくさんのブログをチェックしようとしましたが、このタイプのエラーに対する解決策はないようです。

デイブ

4

2 に答える 2

7

フラッシュによってデータが失われる可能性があるという問題 (または、おそらくどこにも正当化されていない非常に巧妙な機能) がDeflateStreamありますGZipStreamDeflateStream

Response.Flush()フィルターを洗い流します。解決策は、zip と下層のシンクの両方を認識し、後者のみをフラッシュするラッパーを使用することです。

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 をかなりうまく処理します (これは圧縮と解凍の両方に当てはまります)。

于 2010-09-06T19:04:51.160 に答える
0

IISを介してgzipを追加してみましたか?それについて質問がありますので、それが何であるかを見てください。基本的に、IISはすべての圧縮を行うため、必要はありません。

于 2010-09-06T17:32:44.733 に答える