4

如果我在 nginx、uwsgi 和烧瓶中使用分块传输编码,我总是会Content-LengthTransfer-Encoding: chunked. 但是,HTTP 1.1 禁止这种行为。我试图配置 nginx 和 uwsgi 以实现所需的行为(Content-Length在 header 中没有 when Transfer-Encoding: chunked)但没有成功。首先,有我的服务器和客户端代码:

服务器代码(server.py):

from flask import Flask
from flask import request

application = Flask(__name__)

@application.route('/', methods=['PUT'])
def hello():
    print(request.headers)
    print(request.environ.get('SERVER_PROTOCOL'))
    return "Hello World!"

if __name__ == "__main__":
    application.run(host='0.0.0.0')

客户代码(client.py):

import requests

def get_data():
    yield b'This is test file.'
    yield b'This is test file.'

r = requests.request(
    method='PUT',
    url='http://127.0.0.1:5000/',
    data=get_data(),
    headers={
        'Content-type': 'text/plain',
        'X-Accel-Buffering': 'no',
    }
)
print('Response: ', r.text)

如果我运行服务器并尝试使用客户端连接到服务器,我会得到以下输出。服务器输出:

* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
Host: 127.0.0.1:5000
User-Agent: python-requests/2.18.4
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Type: text/plain
X-Accel-Buffering: no
Transfer-Encoding: chunked


HTTP/1.1
[pid: 18455|app: 0|req: 1/1] 127.0.0.1 () {34 vars in 412 bytes} [Wed Jan 17 08:24:53 2018] PUT / => generated 12 bytes in 0 msecs (HTTP/1.1 200) 2 headers in 79 bytes (1 switches on core 0)

客户端输出:

Response:  Hello World!

目前,一切似乎都很好。在标题中,我们Transfer-Encoding没有Content-Length. 现在,我尝试合并 uwsgi ( uwsgi.py):

from server import application

if __name__ == "__main__":
    application.run()

我运行以下命令:

$ uwsgi --http-socket localhost:5000 -w wsgi

输出与之前的尝试相同。因此,还是如预期的那样。现在,我将尝试部署 nginx。我的 uwsgi 配置(uwsgi.ini):

[uwsgi]
module = wsgi

master = true
processes = 5

socket = /tmp/flask.sock
chmod-socket = 777
vacuum = true

die-on-term = true

我的 nginx 配置(/etc/nginx/nginx.conf):

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen 5000;
        server_name 127.0.0.1;

        location / {
            include uwsgi_params;
            uwsgi_pass unix:/tmp/flask.sock;
            proxy_request_buffering off;
            proxy_buffering off;
            proxy_http_version 1.1;
            chunked_transfer_encoding on;
        }
        proxy_request_buffering off;
        proxy_buffering off;
        proxy_http_version 1.1;
        chunked_transfer_encoding on;
    }
}

我启动 nginx,然后运行:

$ uwsgi --ini uwsgi.ini --wsgi-manage-chunked-input --http-raw-body --http-auto-chunked --http-chunked-input

现在,输出包含Content-Length

Content-Type: text/plain
Content-Length: 36
Host: 127.0.0.1:5000
User-Agent: python-requests/2.18.4
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
X-Accel-Buffering: no
Transfer-Encoding: chunked

HTTP/1.1
[pid: 20220|app: 0|req: 1/1] 127.0.0.1 () {42 vars in 525 bytes} [Wed Jan 17 08:31:39 2018] PUT / => generated 12 bytes in 1 msecs (HTTP/1.1 200) 2 headers in 79 bytes (1 switches on core 0)

proxy_request_buffering我为 nginx: , proxy_buffering, proxy_http_versionand chunked_transfer_encodingin the serverand locationcontext尝试了不同的设置,但没有成功。我添加X-Accel-Buffering: no到标题,但它没有解决问题。此外,我为 uwsgi: wsgi-manage-chunked-input, http-raw-body,尝试了不同的选项http-auto-chunkedhttp-chunked-input但没有实现所需的行为(Content-Length仍然存在于带有 的标题中Transfer-Encoding: chunked)。

我使用以下版本的烧瓶、uwsgi 和 nginx:

Flask==0.12.2
uWSGI===2.1-dev-f74553db
nginx 1.12.2-2

知道有什么问题吗?谢谢。

4

1 回答 1

0

我遇到了同样的问题。我的环境是 uWSGI 2.0.17,带有 Nginx 和 Flask 1.0。当客户端发送一个带有 Transfer-Encoding: chunked 的请求时,nginx 添加了 Content-Length。(虽然 HTTP/1.1 协议禁止这样做。)

我的结论是 uWSGI 不支持分块传输编码的请求。当请求标头仅具有 Transfer-Encoding 并且同时具有 Transfer-Encoding 和 Content-Length 时,我的烧瓶应用程序没有获取 POST 方法的请求正文。

Waitress是 python 2 和 3 的 wsgi 服务器,解决了这个问题。如果服务员收到带有 Transfer-Encoding 标头的请求,他将忽略它并设置正确的 Content-Length。(参考https://github.com/Pylons/waitress/blob/c18aa5e24e8d96bb64c9454a626147f37a23f0f0/waitress/parser.py#L154

烧瓶官方文档还推荐服务员运行一个生产烧瓶服务器。(http://flask.pocoo.org/docs/1.0/tutorial/deploy/

于 2018-06-02T16:21:14.913 回答