HTTP流实际上是由HTTP分块实现的吗?

3

起初,我认为http流实际上是通过http分块实现的。

所以我进行了一项测试来学习。

这里是一个Django视图:

def test_stream(request):

    return StreamingHttpResponse(func)

函数返回可迭代对象。使用curl访问该视图,以下是输出结果:

curl -vv -raw http://172.25.44.238:8004/api/v1/admin/restart_all_agent?cluster_id='dd5aef9cbe7311e99585f000ac192cee' -i
Warning: Invalid character is found in given range. A specified range MUST 
Warning: have only digits in 'start'-'stop'. The server's response to this 
Warning: request is uncertain.
* About to connect() to 172.25.44.238 port 8004 (#0)
*   Trying 172.25.44.238...
* Connected to 172.25.44.238 (172.25.44.238) port 8004 (#0)
> GET /api/v1/admin/restart_all_agent?cluster_id=dd5aef9cbe7311e99585f000ac192cee HTTP/1.1
> Range: bytes=aw
> User-Agent: curl/7.29.0
> Host: 172.25.44.238:8004
> Accept: */*
> 
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
Content-Type: text/html; charset=utf-8
< X-Frame-Options: SAMEORIGIN
X-Frame-Options: SAMEORIGIN
* no chunk, no close, no size. Assume close to signal end

< 

some http response body.

* Closing connection 0

从输出结果可以看出没有分块头信息。似乎Http流与分块无关。

那么问题来了

  • http流是由http块实现的吗?
  • 如何在django中返回分块响应?

func() 返回一个可迭代对象吗? - Oleg Russkin
错误的引用,将第一个撇号移到http://的开头 - hanshenrik
实际上,实现是由您的wsgi服务器完成的,您使用什么来测试它(如果是mod_wsgi,则是哪个版本)?而func()应该yield - dirkgroten
@OlegRusskin 是的,该函数返回一个可迭代对象。 - Kramer Li
@dirkgroten 是的。函数返回可迭代对象,我正在使用uwsgi 2.0.18运行django。 - Kramer Li
参数-raw应该改为--raw(两个破折号)。 -raw-r(范围),带有无效范围(aw),在发送请求之前curl也会发出警告。 - axiac
1个回答

2
不,流式传输与分块没有任何关系。你可以有一个有或没有另一个。
流式响应的优点是您不需要一次将整个响应作为字符串加载到内存中。
这篇博客文章做了一个不错的工作,解释了使用情况:https://andrewbrookins.com/django/how-does-djangos-streaminghttpresponse-work-exactly/ 它还涵盖了返回分块响应所需的内容,我将进行总结:
  • 使用StreamingHttpResponse类,但将可迭代对象(列表、生成器等)作为第一个参数提供,而不是字符串。
  • 不要设置Content-Length头。
  • 您需要使用将响应划分为块的Web服务器。Django本身不会执行此操作,并且在manage.py runserver中也不会发生(但是例如uvicorngunicorn会发生)
from django.urls import path
from django.http import StreamingHttpResponse

def generator():
    for i in range(0, 100):
        yield str(i) * 1024 * 1024

def chunked_view(request):
    return StreamingHttpResponse(generator(), content_type='text/plain')

urlpatterns = [path('chunked', chunked_view)]

运行Django应用程序,使用uvicorn myapp.asgi:application命令。
在响应头中,curl -v http://127.0.0.1:8000/chunked > /dev/null会显示transfer-encoding: chunked

1
流式响应的优点在于您不需要一次性将整个响应作为字符串加载到内存中。分块也具有这种优点,因为响应是通过片段返回给客户端的。那么,如果我们已经有了流,为什么还需要分块呢?或者这两种技术有什么区别? - Kramer Li

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