【问题标题】:WebResponse contentLength property is -1?WebResponse contentLength 属性是-1?
【发布时间】:2014-11-12 20:34:58
【问题描述】:

我有一个获取 URL 并下载 .jpeg 文件的 Windows 应用程序。对于某些 url,ContentLength 属性为 -1,因此会引发异常。

这是我的代码:

var url = new Uri(sUrlToReadFileFrom[i]);
_request = (HttpWebRequest)WebRequest.Create(url);
var response = (System.Net.WebResponse)_request.GetResponse();
_response = response;
_response.Close();

这是网址: http://photos.autonexus.com/imager/115-005-CA/P2GTPI4AB9/640/10132013133959/1FAHP0HA3AR373228_1.jpg 以下是关于我的 http 请求的一些信息:

Headers = {Transfer-Encoding: chunked
Connection: keep-alive
Content-Disposition: inline; filename="phpThumb_generated_thumbnail.jpeg"
Content-Type: image/jpeg
Date: Wed, 12 Nov 2014 00:31:29 GMT
Server: nginx
X-Powered-By: PleskLin}

我认为分块标题会导致问题,但我已经用谷歌搜索了 2 天,没有好的解决方案,或者我找不到好的解决方案。

这是错误的屏幕截图:

正如您在第 130 行看到的,因为 _response.ContentLength 已经为 -1,因此 iSize 将为 -1,它会在第 149 行抛出异常。

【问题讨论】:

  • 什么是“它”抛出异常? “它”会抛出什么异常?
  • 我刚刚添加了一个屏幕截图和更多细节。希望对您有所帮助。

标签: c# web httpwebrequest httpwebresponse http-content-length


【解决方案1】:

网站不要求提供 Content-Length 标头,也不能保证它是正确的。所以你不能依赖它。如果您尝试使用ContentLength 属性值来分配数组,或者出于任何目的而不是信息,那么您将遇到麻烦。在一般情况下它根本不可靠。

这很不幸,但你必须解决它。一种解决方案是创建一个MemoryStream。然后从响应流中读取数据块并将它们写入内存流。继续直到响应流结束。然后获取 `MemoryStream' 缓冲区。

有点痛苦,但如果ContentLength 不可靠,这是你能做的最好的事情。

例如:(请注意,我只是把它扔掉了,所以它可能不是 100% 工作。但它应该给你的想法。)

var response = (HttpWebResponse)request.GetResponse();
byte[] data; // will eventually hold the result
// create a MemoryStream to build the result
using (var mstrm = new MemoryStream())
{
    using (var s = response.GetResponseStream())
    {
        var tempBuffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = s.Read(tempBuffer, 0, tempBuffer.Length)) != 0)
        {
            mstrm.Write(tempBuffer, 0, bytesRead);
        }
    }
    mstrm.Flush();
    data = mstrm.GetBuffer();
}
// at this point, the data[] array holds the data read from the stream.
// data.Length will tell you how large it is.

【讨论】:

  • 就像我在回答中所说的那样,您应该使用Stream.CopyTo,因为它的作用完全相同。
【解决方案2】:

很简单:不要使用内容长度标头。如果省略它是完全正常的。只要数据可用,您就应该只读取数据。服务器将继续发送它,直到它完成。您可以使用Stream.CopyTo 方法,它将响应流复制到文件或MemoryStream 或任何东西。该方法也不需要知道长度,它只是一直读取到流结束。

更新:代码是这样的

var resultStream = new MemoryStream()
using (var respStream = response.GetResponseStream())
    respStream.CopyTo(resultStream);
// now you can do anything with resultStream, like resultStream.ToArray()

或者您可以将其写入文件:

using (var fileStream = File.Create(@"d:\x\y.dat"))
using (var respStream = response.GetResponseStream())
    respStream.CopyTo(fileStream);

【讨论】:

  • 您能否详细说明一下。 Jim 和您的 cmets 都是正确的,但我不知道如何将这些想法付诸实践?!
【解决方案3】:

只是为了贡献——Content-Length 标头没有任何问题——服务器将其设置为 -1,因为它正在返回您的数据“分块”——正如您所猜测的那样。分块数据可以是无限的,因此 Content-Length 没有意义。从技术上讲,如果服务器知道它将发送回的块的总大小,它仍然可以返回一个长度,尽管我不知道这是否是规范的一部分。

上面的解决方案可以很好地解决这个问题——但这与 Content-Length 不可靠无关——它与提供它的服务一样可靠。

【讨论】:

    猜你喜欢
    • 2014-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-17
    相关资源
    最近更新 更多