可迭代对象和Django StreamingHttpResponse

6
我想要使用Django连接内部HTTP服务,并需要缓冲这些服务的HTTP响应输出,因为有些内容非常大。
我正在使用Python 3.6、Django 2.0、http.client和以下代码:
class HTTPStreamIterAndClose():
    def __init__(self, conn, res, buffsize):
        self.conn = conn
        self.res = res
        self.buffsize = buffsize
        self.length = 1

        bytes_length = int(res.getheader('Content-Length'))

        if buffsize < bytes_length:
            self.length = math.ceil(bytes_length/buffsize)

    def __iter__(self):
        return self

    def __next__(self):
        buff = self.res.read(self.buffsize)

        if buff is b'':
            self.res.close()
            self.conn.close()

            raise StopIteration
        else:

            return buff

    def __len__(self):
        return self.length


def passthru_http_service(request, server, timeout, path):
    serv = HTTPService(server, timeout)
    res = serv.request(path)

    response = StreamingHttpResponse(
        HTTPStreamIterAndClose(serv.connection, res, 200),
        content_type='application/json'
    )
    response['Content-Length'] = res.getheader('Content-Length')

    return response

响应为空,我使用以下代码测试了迭代器:

b''.join(HTTPStreamIterAndClose(serv.connection, res, 200)

一切都正常工作,我不知道为什么它没有起作用。


浏览器控制台中是否有任何错误? - xyres
不,没有错误。 - Felipe Buccioni
你说的“不工作”是什么意思?你得到了http 500吗?还是200但没有输出?请在你的问题中提供curl -v http://localhost:8000/x/y/(或Postman等)的输出。 - Arman Ordookhani
就像我所说的,空响应,什么都没有 =( - Felipe Buccioni
使用外部连接作为客户端,您将真正看到“发生了什么”!根据您的问题,以这种方式连接到回送地址是不可能的(为流作业定义另一个回送)。 - dsgdfg
显示剩余2条评论
2个回答

4

https://andrewbrookins.com/django/how-does-djangos-streaminghttpresponse-work-exactly/

首先,必须满足以下条件:
  • 客户端必须使用HTTP/1.1或更新的版本
  • 请求方法不能是HEAD
  • 响应中不包含Content-Length
  • 响应状态不是204304
如果这些条件都满足,则Gunicorn会向响应添加Transfer-Encoding: chunked头,向客户端发出响应将以块的形式流式传输的信号。
事实上,即使您使用了HttpResponse,如果这些条件为真,Gunicorn也将响应Transfer-Encoding: chunked
要真正流式传输响应,即将其分段发送到客户端,必须满足这些条件,并且您的响应需要是具有多个项的可迭代对象。
基本上,您需要决定:流式传输还是Content-Length
如果您想要可恢复的下载,请使用Range

这是否适用于其他WSGI服务器? - dahrens
不知道,我没有实验过。 - Krzysztof Szularz

0
最后,问题在于http请求在一些毫秒后断开连接,这就是为什么当我在连接之后立即迭代而不是在创建对象之前工作正常,但当我在响应之后使用时不起作用。但是当我在开始迭代时启动连接时,一切都完美地运行 =/。
干杯。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接