无论 Content-Type 标头是什么,都可以在 Python Flask 中获取原始 POST 正文
- 2025-03-11 08:54:00
- admin 原创
- 69
问题描述:
之前我问过如何获取 Flask 请求中收到的数据,因为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
解决方案 1:
用于request.get_data()
获取原始数据,无论内容类型如何。数据被缓存,您随后可以随意访问request.data
、request.json
、 。request.form
如果您request.data
先访问,它将get_data
使用参数调用以先解析表单数据。如果请求具有表单内容类型(multipart/form-data
、application/x-www-form-urlencoded
或application/x-url-encoded
),则将使用原始数据。在这种情况下request.data
将request.json
显示为空。
解决方案 2:
request.stream
是 WSGI 服务器传递给应用程序的原始数据流。读取时不会进行解析,尽管您通常希望request.get_data()
这样做。
data = request.stream.read()
request.data
如果先前已用或其他属性读取该流,则该流将为空。
解决方案 3:
我创建了一个 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']
解决方案 4:
request.data
`request.headers["Content-Type"]如果被识别为表单数据,则为空,将被解析为
request.form。要获取原始数据(无论内容类型如何),请使用
request.get_data()`。
request.data
调用request.get_data(parse_form_data=True)
,这会导致表单数据的行为不同。
扫码咨询,免费领取项目管理大礼包!