Skip to main content
 首页 » 编程设计

使用 httplib 发送 Python HTTPConnection 文件,检索进度

2025年05月04日11Terrylee

在 Django 应用程序中,我使用第三方 Python script允许用户通过 EC2 实例上的 httplib.HTTPConnection.send 将文件上传到 blip.tv。由于这些文件一般都很大,我会使用消息队列异步处理上传(RabbitMQ/Celery),并在前端向用户反馈进度。

httpconnection 和 send 是在这部分脚本中完成的:

host, selector = urlparts = urlparse.urlsplit(url)[1:3] 
h = httplib.HTTPConnection(host) 
h.putrequest("POST", selector) 
h.putheader("content-type", content_type) 
h.putheader("content-length", len(data)) 
h.endheaders() 
h.send(data)     
response = h.getresponse() 
return response.status, response.reason, response.read()   

文件传输完成后返回了getresponse(),我如何写出进度(假设有stdout.write),以便我可以将这个值写入缓存框架进行显示(djangosnippets 678/679)?或者,如果有更好的做法,我会洗耳恭听!

编辑:

自从我使用了 urllib2 并使用了来自 this question 的提示覆盖文件的 read() 以获取上传进度。此外,我正在使用海报生成多部分 urlencode。这是最新的代码:

from poster.encode import multipart_encode 
from poster.streaminghttp import register_openers 
def Upload(video_id, username, password, title, description, filename): 
 
    class Progress(object): 
        def __init__(self): 
            self._seen = 0.0 
 
        def update(self, total, size, name): 
            self._seen += size 
            pct = (self._seen / total) * 100.0 
            print '%s progress: %.2f' % (name, pct) 
 
    class file_with_callback(file): 
        def __init__(self, path, mode, callback, *args): 
            file.__init__(self, path, mode) 
            self.seek(0, os.SEEK_END) 
            self._total = self.tell() 
            self.seek(0) 
            self._callback = callback 
            self._args = args 
 
        def __len__(self): 
            return self._total 
 
        def read(self, size): 
            data = file.read(self, size) 
            self._callback(self._total, len(data), *self._args) 
            return data 
 
    progress = Progress() 
    stream = file_with_callback(filename, 'rb', progress.update, filename) 
 
    datagen, headers = multipart_encode({ 
                                        "post": "1", 
                                        "skin": "xmlhttprequest", 
                                        "userlogin": "%s" % username, 
                                        "password": "%s" % password, 
                                        "item_type": "file", 
                                        "title": "%s" % title.encode("utf-8"), 
                                        "description": "%s" % description.encode("utf-8"),                                              
                                         "file": stream 
                                         })     
 
    opener = register_openers() 
 
    req = urllib2.Request(UPLOAD_URL, datagen, headers) 
    response = urllib2.urlopen(req) 
    return response.read() 

这只适用于文件路径输入,而不是来自表单输入(request.FILES)的 InMemoryUploadedFile,因为我想它正在尝试读取已经保存在内存中的文件,并且我在线上遇到了 TypeError : "stream = file_with_callback(filename, 'rb', progress.update, filename)":

coercing to Unicode: need string or buffer, InMemoryUploadedFile found 

如何实现与用户上传文件相同的进度报告?另外,像这样读取进度会不会消耗大量内存,也许是这个download progress for urllib2的上传解决方案会更好,但是如何实现...非常欢迎帮助

请您参考如下方法:

事实证明,poster库在 multipart_encode 中有一个回调 Hook ,可用于获取进度(上传或下载)。好东西...

虽然我想我在技术上回答了这个问题,但我确信还有其他方法可以给这只猫剥皮,所以如果我找到其他方法或细节,我会发布更多。

代码如下:

def prog_callback(param, current, total): 
    pct = 100 - ((total - current ) *100 )/ (total)  
    print "Progress: %s " % pct     
 
 
datagen, headers = multipart_encode({ 
                                    "post": "1", 
                                    "skin": "xmlhttprequest", 
                                    "userlogin": "%s" % username, 
                                    "password": "%s" % password, 
                                    "item_type": "file", 
                                    "title": "%s" % title.encode("utf-8"), 
                                    "description": "%s" % description.encode("utf-8"),                                              
                                     "file": filename 
                                     }, cb=prog_callback)     
 
opener = register_openers() 
 
req = urllib2.Request(UPLOAD_URL, datagen, headers) 
response = urllib2.urlopen(req) 
return response.read()