在没有提供Content-Length的情况下用Python正确下载文件
我该如何在Python中正确下载一个文件,如果HTTP响应中没有包含Content-Length这个头信息呢?
我在使用appengine的send_blob()函数时遇到了这个问题,出于某种原因,对于较大的(20MB以上)文件,它并没有添加Content-Length这个头信息。
现在我在使用urllib.urlretrieve(),但有时候它并不能下载完整个文件。 我现在的做法是在下载文件之前先发送内容长度,这样我可以在继续下载之前检查文件的大小是否正确。
我不太确定有没有更好的方法来做到这一点。
这是其中一个文件的头信息:
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: application/octet-stream
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Date: Fri, 30 Sep 2011 19:41:34 GMT
Server: Google Frontend
Transfer-Encoding: Identity
Connection: close
我刚刚尝试用wget下载一个文件,使用的命令是 wget --server-response --continue
,得到的头信息是:
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: application/octet-stream
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Date: Wed, 05 Oct 2011 14:08:13 GMT
Server: Google Frontend
Transfer-Encoding: chunked
Length: unspecified [application/octet-stream]
2 个回答
如果服务器没有告诉你请求的数据有多长,先给你发了一些数据,然后就关闭了连接,那么HTTP客户端必须假设这些数据都已经成功传输了。
只有使用额外的、非HTTP的信息,比如校验和或其他错误修正方法,应用程序才能判断是否发生了错误,并在后续的客户端请求中使用HTTP范围头(也就是Range: bytes=NNNN-
)来继续传输。
如果服务器不支持Range
头,你可以通过服务器在任何时候发送的响应头Accept-Ranges: none
来判断。那么据我所知,你对这个有问题的服务器实现没有其他办法,只能定期重试请求,希望它最终能给出一个通过错误检测的响应。
附注:我并不惊讶在提供大块内容时Content-Length
头缺失。许多数据库API不允许在不实际获取整个内容的情况下测试大块的长度。我猜这可能是因为SQL引擎本身不支持这个测试。
App Engine正在使用一种叫做分块编码的方式发送响应,这种方式让客户端可以知道响应什么时候结束。不过,通常情况下,urllib应该会帮你处理这些事情。看起来你的连接可能因为某种原因被过早地断开了,而urllib没有把这个情况告诉你(或者你捕捉到了这个错误但没有去处理它)。