2010-09-06 87 views
4

的最後一部分,我創建了一個叫做AddGZip擴展方法,看起來像以下:GZipStream被切斷XML

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 Parsing Error: unclosed token Location: http://webserver1/1234.xml Line Number 78, Column 1:"

Wh我查看源代碼,它基本上錯過了XML文件末尾的最後一個>。所以1或2個字節。

如果我註釋掉AddGZip線,它工作正常。但是我真的想要支持GZip,因爲XML可能非常大。

有人對我有什麼建議嗎?我試過檢查很多博客,但沒有解決方案似乎在這種類型的錯誤。

Dave

+0

Ooo 1我應該說的事情是,我使用IIS 6.0 – CraftyFella 2010-09-06 17:35:03

回答

7

有一個問題(或者可能是一個很聰明的功能,我還沒有看到任何地方合理)與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的壓縮。

+0

嗨,謝謝你..我試了一下,但它似乎沒有任何區別。有一件事很奇怪,就是我的例子和你的工作在IIS 7.0上運行正常,所以我想知道它是不是在IIS 6.0上安裝得很好?我將我的代碼更改爲 response.Filter = new WebCompressionFilter(response.Filter,CompressionType.GZip); 任何想法? – CraftyFella 2010-09-07 10:38:30

+0

上面已經在IIS 5到7上爲我工作了。告訴我,如果您註釋掉所有對Response.Flush()的調用,問題是否仍然存在。可能我們正在修復錯誤的問題,根本就不是那種衝突問題。 – 2010-09-07 10:46:47

+0

也許還要檢查Close()是否被調用(應該發生在你可能做的任何事情上)。最後,有一個直接實現的過濾器的好處是,你現在已經有了一些地方可以掛鉤一些日誌記錄,並確保應該寫入它的所有內容實際上都是,如果錯誤的來源實際上是在其他地方。 – 2010-09-07 10:50:21

0

您是否嘗試過通過IIS添加gzip?有關於它的question,所以看看它是什麼。基本上,IIS會進行所有壓縮,因此您不必這樣做。