You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask 2.0.2中使用request.json与Postman发送POST请求时JSON解码失败问题排查

问题排查:Flask接口中request.json解码失败的原因及解决办法

这问题我太熟了!你遇到的核心问题是WSGI的请求体输入流只能被读取一次,你的中间件先把流读空了,导致后面Flask的Request对象再去解析JSON时根本拿不到数据。

具体原因分析

在你的GlobalAuth中间件里,你创建了一个Werkzeug的Request实例并调用了request.json:

request = Request(environ)
args = request.args
body_args = request.json

当调用request.json时,Werkzeug会读取environ['wsgi.input']这个输入流里的所有数据来解析JSON。而WSGI规范里,这个输入流是一次性的——读完之后指针就到了末尾,后续再读取就只能拿到空内容了。

而你的Flask接口里的request对象,是在中间件处理完成之后才创建的,这时候它再去读取wsgi.input,已经没有任何数据了,自然会抛出"Failed to decode JSON object"的错误。哪怕你加了request.on_json_loading_failed也没用,因为根本就没有可解码的内容。

解决方案

有两种常用的修复方式,你可以根据需求选择:

方案1:中间件读取后重置输入流

如果中间件必须要读取JSON数据,那在读取完之后要把输入流的指针重置到开头,这样后续Flask的Request还能读到数据:

from werkzeug.wsgi import get_input_stream

class GlobalAuth:
    ''' Simple WSGI middleware '''
    def __init__(self, app):
        self.app = app
    def __call__(self, environ, start_response):
        # 先读取流并保存数据
        input_stream = get_input_stream(environ)
        data = input_stream.read()
        # 重置流指针到开头
        environ['wsgi.input'].seek(0)
        
        # 现在可以解析JSON了
        request = Request(environ)
        args = request.args
        body_args = request.json
        
        # 继续处理请求
        return self.app(environ, start_response)

注意:不是所有WSGI服务器的输入流都支持seek操作,这种方式可能在某些环境下不兼容。

方案2:将解析后的JSON存入environ,后续直接复用

更稳妥的方式是,中间件解析完JSON后,把结果存入environ的自定义字段里,这样Flask接口里就不用再去读取流,直接从environ里取:

import json
from werkzeug.wsgi import get_input_stream

class GlobalAuth:
    ''' Simple WSGI middleware '''
    def __init__(self, app):
        self.app = app
    def __call__(self, environ, start_response):
        input_stream = get_input_stream(environ)
        data = input_stream.read()
        # 重置流指针,避免影响其他可能读取流的逻辑
        environ['wsgi.input'].seek(0)
        
        # 解析JSON并存入environ
        try:
            body_args = json.loads(data) if data else {}
            environ['middleware_parsed_json'] = body_args
        except json.JSONDecodeError:
            environ['middleware_parsed_json'] = None
        
        # 继续处理请求
        return self.app(environ, start_response)

然后在你的Test接口里,直接使用中间件解析好的数据:

class Test(Resource):
    @staticmethod
    def post():
        # 从environ中获取中间件解析好的JSON
        data = request.environ.get('middleware_parsed_json', {})
        return make_response(data,200)

这种方式兼容性更好,也避免了重复解析JSON的开销。

额外提醒

另外,你代码里的request.on_json_loading_failed(e="a")用法其实不对,这个方法是用来设置自定义的加载失败回调函数,不是直接传入错误信息。正确的用法应该是:

def handle_json_error(e):
    return make_response({"error": "Invalid JSON"}, 400)

request.on_json_loading_failed = handle_json_error

不过这个在你当前的问题里不是核心,解决了流被消耗的问题之后,这个错误自然就不会出现了。

内容的提问来源于stack exchange,提问作者Anabel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 03:17:31