在 PythonFlask 中获取原始 POST 主体,而不管 Content-Type 头是什么

以前,我问 如何在烧瓶请求中获得接收到的数据是因为 request.data是空的。答案解释说,request.data是原始的后台主体,但是如果解析表单数据,它将是空的。我怎样才能无条件地得到生的柱体?

@app.route('/', methods=['POST'])
def parse_request():
data = request.data  # empty in some cases
# always need raw data here, not parsed form data
173162 次浏览

request.stream 是 WSGI 服务器传递给应用程序的原始数据流。读取时不执行解析,尽管通常需要使用 request.get_data()

data = request.stream.read()

如果以前由 request.data或其他属性读取该流,则该流将为空。

我创建了一个 WSGI 中间件,它存储来自 environ['wsgi.input']流的原始主体。我在 WSGI 环境中保存了这个值,这样我就可以在我的应用程序中从 request.environ['body_copy']访问它。

这在 Werkzeug 或 Flask 中没有必要,因为不管内容类型如何,request.get_data()都会获得原始数据,但是对 HTTP 和 WSGI 行为有更好的处理。

这会将整个主体读入内存,如果发布了大型文件,这将是一个问题。如果 Content-Length报头丢失,这将不会读取任何内容,因此它不会处理流请求。

from io import BytesIO


class WSGICopyBody(object):
def __init__(self, application):
self.application = application


def __call__(self, environ, start_response):
length = int(environ.get('CONTENT_LENGTH') or 0)
body = environ['wsgi.input'].read(length)
environ['body_copy'] = body
# replace the stream since it was exhausted by read()
environ['wsgi.input'] = BytesIO(body)
return self.application(environ, start_response)


app.wsgi_app = WSGICopyBody(app.wsgi_app)
request.environ['body_copy']

使用 request.get_data()获取原始数据,与内容类型无关。数据被缓存,随后您可以随意访问 request.datarequest.jsonrequest.form

如果您首先访问 request.data,它将使用一个参数调用 get_data,以便首先解析表单数据。如果请求具有表单内容类型(multipart/form-dataapplication/x-www-form-urlencodedapplication/x-url-encoded) ,那么将使用原始数据。在这种情况下,request.datarequest.json将显示为空。

如果 request.headers["Content-Type"]被识别为表单数据,那么 request.data将为空,表单数据将被解析为 request.form。若要获取原始数据,而不管内容类型如何,请使用 request.get_data()

request.data调用 request.get_data(parse_form_data=True),这将导致表单数据的不同行为。