【问题标题】:Automatically decompress gzip response via WebClient.DownloadData通过 WebClient.DownloadData 自动解压 gzip 响应
【发布时间】:2011-02-27 17:29:29
【问题描述】:

我希望自动解压缩 GZiped 响应。 我正在使用以下 sn-p:

mywebclient.Headers[HttpRequestHeader.AcceptEncoding] = "gzip";
mywebclient.Encoding = Encoding.UTF8;

try
{
    var resp = mywebclient.DownloadData(someUrl);
}

我已经检查了HttpRequestHeader enum,没有选项可以通过Headers 执行此操作

我怎样才能自动解压resp?或者我应该使用另一个函数来代替mywebclient.DownloadData 吗?

【问题讨论】:

    标签: .net gzip webclient


    【解决方案1】:

    WebClient 在幕后使用 HttpWebRequest。并且 HttpWebRequest 支持 gzip/deflate 解压。见HttpWebRequest AutomaticDecompression property

    但是,WebClient 类不直接公开此属性。所以你必须从它派生来设置底层 HttpWebRequest 的属性。

    class MyWebClient : WebClient
    {
        protected override WebRequest GetWebRequest(Uri address)
        {
            HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
            request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
            return request;
        }
    }
    

    【讨论】:

    • 这里有什么特别的理由使用“过度使用”(恕我直言)作为铸造而不是“传统铸造”吗?如果你使用 as,你肯定应该检查请求是非空的,所以我想知道在这种情况下假设 GetWebRequest() 的结果总是一个 HttpWebRequest 是否会更简单......
    • 不幸的是,这不适用于 WP8.1 Silverlight 项目。属性“AutomaticDecompression”不可用。有什么想法我应该做什么?谢谢!
    【解决方案2】:

    根据你的情况,自己解压可能更简单。

    using System.IO.Compression;
    using System.Net;
    
    try
    {
        var client = new WebClient();
        client.Headers[HttpRequestHeader.AcceptEncoding] = "gzip";
        var responseStream = new GZipStream(client.OpenRead(myUrl), CompressionMode.Decompress);
        var reader = new StreamReader(responseStream);
        var textResponse = reader.ReadToEnd();
    
        // do stuff
    
    }
    

    为了清楚起见,我创建了所有临时变量。这都可以展平为只有clienttextResponse

    或者,如果简单是目标,您甚至可以使用ServiceStack.Text by Demis Bellot

    using ServiceStack.Text;
    
    var resp = "some url".GetJsonFromUrl();
    

    (还有其他.Get*FromUrl扩展方法)

    【讨论】:

    • 我不确定 client.OpenRead 是否尊重 webClient 实例的编码集
    • 需要注意的是:您必须真正读取 gzip 流才能解压缩;试图用responseStream.CopyTo( File.OpenWrite(...) ) 之类的东西变得聪明是行不通的