WSGI 到 ASGI 的适配器到底做了什么?环境字典里少了什么?流式响应经过它们会怎样?这篇用 Flask 的 request.environ 把四种适配方式摊开对比,并亲手写一个最小适配器。
[gunicorn(原生 WSGI)] 键 24 个
比 gunicorn 多出:[]
比 gunicorn 少了:[]
[uvicorn + a2wsgi] 键 19 个
比 gunicorn 多出:['asgi.scope']
比 gunicorn 少了:['RAW_URI', 'SERVER_SOFTWARE', 'gunicorn.socket', 'wsgi.early_hints', 'wsgi.file_wrapper', 'wsgi.input_terminated']
[uvicorn + asgiref WsgiToAsgi] 键 17 个
比 gunicorn 多出:[]
比 gunicorn 少了:['RAW_URI', 'REMOTE_PORT', 'SERVER_SOFTWARE', 'gunicorn.socket', 'wsgi.early_hints', 'wsgi.file_wrapper', 'wsgi.input_terminated']
[uvicorn + 自己写的 mini 适配器] 键 18 个
比 gunicorn 多出:['CONTENT_LENGTH']
比 gunicorn 少了:['RAW_URI', 'REMOTE_PORT', 'SERVER_SOFTWARE', 'gunicorn.socket', 'wsgi.early_hints', 'wsgi.file_wrapper', 'wsgi.input_terminated']
几个关键值:
gunicorn(原生 WSGI) SERVER_NAME=127.0.0.1 REMOTE_ADDR=127.0.0.1 wsgi.url_scheme=http wsgi.multithread=True wsgi.input=Body
uvicorn + a2wsgi SERVER_NAME=127.0.0.1 REMOTE_ADDR=127.0.0.1 wsgi.url_scheme=http wsgi.multithread=True wsgi.input=Body
uvicorn + asgiref WsgiToAsgi SERVER_NAME=127.0.0.1 REMOTE_ADDR=127.0.0.1 wsgi.url_scheme=http wsgi.multithread=True wsgi.input=SpooledTemporaryFile
uvicorn + 自己写的 mini 适配器 SERVER_NAME=127.0.0.1 REMOTE_ADDR=127.0.0.1 wsgi.url_scheme=http wsgi.multithread=True wsgi.input=BytesIO上一篇:Flask 与 ASGI;下一篇:Greenlet 与 Flask Context。
gunicorn(原生 WSGI) 2 MB 请求体读到 2097152 字节 | 流式响应各块到达(ms):[1, 312, 618, 923, 1232] uvicorn + a2wsgi 2 MB 请求体读到 2097152 字节 | 流式响应各块到达(ms):[1, 305, 609, 920, 1223] uvicorn + asgiref WsgiToAsgi 2 MB 请求体读到 2097152 字节 | 流式响应各块到达(ms):[2, 304, 611, 916, 1221] uvicorn + 自己写的 mini 适配器 2 MB 请求体读到 2097152 字节 | 流式响应各块到达(ms):[1233, 1233, 1233, 1233, 1234]
GET /hello → 200 hi GET /nope → 404