HTTP 报文的组成
Response 报文由:
- 状态行 start-line
- 响应头 HTTP headers
- 空行 empty-line
- 响应体 body
四部分组成
参考资料:
mozilla doc:Date
http里的时间格式
好了下面是问题的正文了
我发现一般的 HTTP 服务器在发送 Response
报文的时候,是把(状态行、响应头、空行)作为一个整体发送(即调用一次 socket.send()),然后在调用一次 socket.send() 把响应体 body
发出去。
看了 Gunicorn 服务器,和 aiohttp
为什么不一次发送呢?
下面是 Gunicorn 的两段源代码:
gunicorn/http/wsgi.py
def create(req, sock, client, server, cfg):
resp = Response(req, sock, cfg)
environ = default_environ(req, sock, cfg)
# ...
environ['PATH_INFO'] = util.unquote_to_wsgi_str(path_info)
environ['SCRIPT_NAME'] = script_name
# ....
return resp, environ
class Response(object):
def start_response(self, status, headers, exc_info=None):
# ...
self.status = status
self.process_headers(headers)
return self.write
def write(self, arg):
self.send_headers() # 可以看到一句 self.send_headers(), 单独发出了 headers
# ...
util.write(self.sock, arg, self.chunked)
可以看到一句 self.send_headers()
, 单独发出了 headers
gunicorn/util.py
def write(sock, data, chunked=False):
if chunked:
return write_chunk(sock, data)
sock.sendall(data)
下面是一段 aiohttp
的 demo 代码。
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as resp:
if resp.status != 200:
resp.raise_for_status()
data = await resp.text()
return data
比如 aiohttp
在获取 response.text
的时候会加一个 await
,我不明白为什么要加 await
,因为客户端接收到 response
的时候,已经包含 text
了呀,为什么还要加一个 await
呢?除非是 text 是单独发送的,所以才会有 IO 等待的问题,是这样吗?
总结一下,问题的核心就是一般的 HTTP 服务器(nginx
、 httpd
、 tomcat
、 uwsgi
等等),在调用 socket 的 send 给 client 发送 HTTP response 的时候,是不是都是先调用一次 socket.send
发送不包含 body 的部分,在调用 N 次发送 body
的呢?