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 压缩的主要内容,如果未能解决你的问题,请参考以下文章