HttpWebRequest 和原生 GZip 压缩

Posted

技术标签:

【中文标题】HttpWebRequest 和原生 GZip 压缩【英文标题】:HttpWebRequest & Native GZip Compression 【发布时间】:2010-10-24 19:17:17 【问题描述】:

当请求使用 Gzip 压缩的页面时,我收到很多以下错误:

System.IO.InvalidDataException: GZip 页脚中的 CRC 与 从解压后计算出的 CRC 数据

我正在使用本机 GZipStream 解压缩并正在考虑解决此问题。考虑到这一点,是否有解决这个或另一个 GZip 库(免费?)的解决方法,可以正确处理这个问题?

我正在验证 webResponse ContentEncoding 是 GZIP

5/11 更新 一个简化的代码段

//Caller
public void SOSampleGet(string url) 

    // Initialize the WebRequest.
    webRequest = (HttpWebRequest)WebRequest.Create(url);
    webRequest.Method = WebRequestMethods.Http.Get;
    webRequest.KeepAlive = true;
    webRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
    webRequest.Headers.Add("Accept-Encoding", "gzip,deflate");
    webRequest.Referer = WebUtil.GetDomain(url);

    HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();    

    using (Stream stream = GetStreamForResponse(webResponse, READTIMEOUT_CONST))
    
        //use stream
    


//Method
private static Stream GetStreamForResponse(HttpWebResponse webResponse, int readTimeOut)

    Stream stream;
    switch (webResponse.ContentEncoding.ToUpperInvariant())
    
        case "GZIP":
            stream = new GZipStream(webResponse.GetResponseStream(), CompressionMode.Decompress);
            break;
        case "DEFLATE":
            stream = new DeflateStream(webResponse.GetResponseStream(), CompressionMode.Decompress);
            break;

        default:
            stream = webResponse.GetResponseStream();
            stream.ReadTimeout = readTimeOut;
            break;
            
    return stream;

【问题讨论】:

是针对特定网站,还是来自各地的响应?如果它只有一个站点,则问题可能出在另一侧。 另请注意,根据 HTTP 规范,“deflate”实际上是“zlib”(包装了 deflate),根本不是 deflate(用词不当)。但是,由于this confusion,一些服务器将发送deflate 和其他zlib,并且客户端需要同时支持两者(通过启发式猜测)以防万一。糟糕。 【参考方案1】:

从 .net 2 开始提供的 webrequest AutomaticDecompression 属性怎么样?只需添加:

webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

它还将 gzip,deflate 添加到接受编码标头中。

见http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.automaticdecompression.aspx

【讨论】:

你会如何使用 HttpClient 来做到这一点? @MartinKearn,你做HttpClientHandler handler = new HttpClientHandler(); handler.AutomaticDecompression = System.Net.DecompressionMethods.GZip | DecompressionMethods.Deflate; _client = new HttpClient(handler); 见***.com/questions/20990601/… 我相信它需要.net 4.5。【参考方案2】:

对于 .NET Core,涉及的内容要多一些。需要GZipStream,因为AutomaticCompression 没有属性(截至撰写时)。在这里查看我的答案:https://***.com/a/44508724/2421277

答案代码:

var req = WebRequest.CreateHttp(uri);

/*
 * Headers
 */
req.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate";

/*
 * Execute
 */
try

    using (var resp = await req.GetResponseAsync())
    
        using (var str = resp.GetResponseStream())
        using (var gsr = new GZipStream(str, CompressionMode.Decompress))
        using (var sr = new StreamReader(gsr))

        
            string s = await sr.ReadToEndAsync();  
        
    

catch (WebException ex)

    using (HttpWebResponse response = (HttpWebResponse)ex.Response)
    
        using (StreamReader sr = new StreamReader(response.GetResponseStream()))
        
            string respStr = sr.ReadToEnd();
            int statusCode = (int)response.StatusCode;

            string errorMsh = $"Request (url) failed (statusCode) on, with error: respStr";
        
    

【讨论】:

【参考方案3】:

您是否正在刷新和关闭流?尝试使用 Using 语句包装您的 GZipStream。

【讨论】:

它被包裹在 finally 块中流的 Try/Catch/Finally 调用 Dispose() 中。【参考方案4】:

我找到了一些示例代码,显示了 GZip 编码页面的整个请求/响应。它使用 GZipStream。

http://www.know24.net/blog/Decompress+GZip+Deflate+HTTP+Responses.aspx

【讨论】:

链接已损坏,但我通过archive.org 进行了查找,基本方法效果很好:) 对于和我一样不熟悉archive.org的人来说,新链接是:web.archive.org/web/20200214173529/http://www.know24.net/blog/…【参考方案5】:

请参阅我上面的评论,但这通常是文件损坏的症状。如果该站点是您自己的,请替换您尝试访问的文件。

【讨论】:

不是我的网站,但对于我请求的一些网站来说似乎是特别的。【参考方案6】:

本机 GZipStream 可以读取压缩的 GZIP (RFC 1952) 流,但无法处理 ZIP 文件格式。

来自http://www.geekpedia.com/tutorial190_Zipping-files-using-GZipStream.html:

使用的缺点 第三方的 GZipStream 类 产品是它有限制 能力。限制之一 是你不能给 您放置在存档中的文件。 当 GZipStream 压缩文件时 到 ZIP 存档中,它需要 该文件中的字节序列和 使用压缩算法 创建一个较小的字节序列。 新的字节序列被放入 新的 ZIP 文件。当你打开 ZIP 文件,您将打开存档 文件本身;最流行的邮编 提取器(WinZip、WinRar 等)将 将 ZIP 的内容显示为 与存档相同的文件 自己。


编辑:以上注释不正确。 GZipStream 不生成 ZIP 文件。它不是“单文件 ZIP 流”。它是一个 GZIP 流。它们是不同的东西。无法保证处理 ZIP 档案的工具能够处理 .gz 文件。


对于可以读取 ZIP 存档(而不是单文件 ZIP 流)的实现,请尝试 #ziplib (SharpZipLib, formerly NZipLib)。

【讨论】:

我不相信原始发帖人在谈论处理压缩/存档文件。相反,用例是在向服务器发送 Accept-Encoding: 标头时请求网页,表明客户端支持 gzip。该标头允许服务器在将内容发送到客户端之前对其进行压缩,从而节省带宽。现代网络浏览器可以做到这一点,并且许多服务器都被配置为做出相应的响应。 您是否在检查服务器是否真的回复了 gzip 流,例如使用 wireshark? Wireshark 可以解码和验证回复,即使它是 gzip 压缩的。

以上是关于HttpWebRequest 和原生 GZip 压缩的主要内容,如果未能解决你的问题,请参考以下文章

GZIP 头解析

如何实现,读取远程文件,用GZIP压缩后保存成文件

gzip 命令

Linux-(tar,gzip)

ajax调用handler,使用HttpWebRequest访问WCF服务

开启gzip压缩