Frage

Ich habe eine Erweiterungsmethode erstellt genannt AddGZip die aussieht wie die folgende:

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

Dies ist eine sehr abgespeckte Version des Codes:

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();

Wenn Sie die Antwort in einem Web-Browser mit gzip Unterstützung sehen Sie eine Fehlermeldung wie diese:

  

"XML-Parsing-Fehler: unclosed Token   Ort: http: //webserver1/1234.xml   Zeilennummer 78, Spalte 1: "

Wenn ich die Quelle anzeigen es ist im Grunde aus dem letzten > vom Ende der XML-Datei verpaßt. So 1 oder 2 Bytes.

Wenn ich die AddGZip Linie kommentieren Sie es funktioniert gut. Allerdings will ich wirklich GZip unterstützen, wie die XML recht groß sein kann.

Hat jemand einen Vorschlag für mich? Ich habe versucht, viele Blogs überprüft, aber keine Lösung scheint es erwiesen, für diese Art von Fehlern.

Dave

War es hilfreich?

Lösung

Es gibt ein Problem (oder vielleicht ein wirklich cleveres Feature, dass ich nicht gerechtfertigt irgendwo gesehen habe) mit DeflateStream (GZipStream baut auf DeflateStream und erbt die Frage *), wo Spülung Daten verloren gehen kann.

Response.Flush() die Filter spülen. Die Lösung ist ein Wrapper zu verwenden, die sowohl sich der Zuziehen ist und der darunter liegenden Wanne und nur spült den letzteren:

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);
    }
}

Es ist auch erwähnenswert, dass die meisten User-Agents, dass die Unterstützung gzip-kodierenden auch Unterstützung deflate-Codierung. Während die Größe Verbesserung mit deflate ist negliable (buchstäblich nur ein paar Bytes), erheblich einige Bibliotheken auf einige Architektur beschäftigt sich mit deflate besser (diese beiden geht zum Komprimieren und Dekomprimieren), so ist es immer wert begünstigende deflate über gzip mit HTTP-Komprimierung.

Andere Tipps

Haben Sie versucht, gzip durch IIS hinzufügen? Es gibt eine Frage darüber, so schauen, was es geht um . Grundsätzlich ist die IIS macht die ganze Kompression so dass Sie nicht haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top