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

Flask API报错TypeError:协程对象无法JSON序列化问题求助

问题原因分析

你遇到的TypeError: Object of type coroutine is not JSON serializable本质是Flask/Flask-RESTful默认不支持异步装饰器直接装饰同步视图:

  • 你的require_api_key_from_db装饰器返回的是异步wrapper函数,当Flask调用这个装饰后的视图方法时,得到的是一个coroutine对象,而非标准的响应元组/字典;
  • 同时你在wrapper里用await func(*args, **kwargs)调用同步视图方法,会把同步函数包装成coroutine,最终返回的result也是coroutine,Flask尝试将其序列化为JSON时自然报错。
修复方案

方案1:改用异步视图(推荐,Flask 2.0+支持)

将Resource中的同步方法改为异步方法,利用Flask 2.0及以上版本的原生异步支持:

from flask import Flask, request
from functools import wraps
import asyncio
from flask import jsonify

from flask_restful import Resource, Api, reqparse
from database import DataBase

app = Flask(__name__)
api = Api(app)

database = DataBase()

data_storage = {}

def require_api_key_from_db(func):
    @wraps(func)
    async def wrapper(*args, **kwargs):
        api_key = request.headers.get("X-API-Key")
        if api_key:
            user_id = await database.get_user_id_by_api_key(api_key)
            if user_id is None:
                return {"error": "Unauthorized 2"}, 401
            else:
                kwargs["user_id"] = user_id
                result = await func(*args, **kwargs)
                return result
        return {"error": "Unauthorized"}, 401

    return wrapper

class DataResource(Resource):
    method_decorators = [require_api_key_from_db]

    # 改为async方法
    async def get(self, key):
        if key in data_storage:
            return {key: data_storage[key]}
        else:
            return {"error": "Not Found"}, 404

    async def put(self, key):
        parser = reqparse.RequestParser()
        parser.add_argument("value", type=str, required=True, help="Value cannot be blank.")
        args = parser.parse_args()

        data_storage[key] = args["value"]
        return {key: data_storage[key]}

    async def delete(self, key):
        if key in data_storage:
            del data_storage[key]
            return {"result": "Deleted successfully"}
        else:
            return {"error": "Not Found"}, 404

api.add_resource(DataResource, "/data/<string:key>")

if __name__ == "__main__":
    app.run(debug=True)

方案2:将异步操作同步化(兼容旧版Flask)

如果无法升级Flask版本,可在装饰器中手动运行asyncio事件循环,把异步数据库调用转为同步执行:

from flask import Flask, request
from functools import wraps
import asyncio
from flask import jsonify

from flask_restful import Resource, Api, reqparse
from database import DataBase

app = Flask(__name__)
api = Api(app)

database = DataBase()

data_storage = {}

def require_api_key_from_db(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        api_key = request.headers.get("X-API-Key")
        if api_key:
            # 运行异步函数并获取结果,转为同步操作
            user_id = asyncio.run(database.get_user_id_by_api_key(api_key))
            if user_id is None:
                return {"error": "Unauthorized 2"}, 401
            else:
                kwargs["user_id"] = user_id
                # 直接调用同步视图方法,无需await
                result = func(*args, **kwargs)
                return result
        return {"error": "Unauthorized"}, 401

    return wrapper

class DataResource(Resource):
    method_decorators = [require_api_key_from_db]

    # 保持原同步方法不变
    def get(self, key):
        if key in data_storage:
            return {key: data_storage[key]}
        else:
            return {"error": "Not Found"}, 404

    def put(self, key):
        parser = reqparse.RequestParser()
        parser.add_argument("value", type=str, required=True, help="Value cannot be blank.")
        args = parser.parse_args()

        data_storage[key] = args["value"]
        return {key: data_storage[key]}

    def delete(self, key):
        if key in data_storage:
            del data_storage[key]
            return {"result": "Deleted successfully"}
        else:
            return {"error": "Not Found"}, 404

api.add_resource(DataResource, "/data/<string:key>")

if __name__ == "__main__":
    app.run(debug=True)
关键注意点
  • 方案1需确保Flask版本≥2.0,否则异步视图无法正常运行;
  • 方案2中asyncio.run()会创建新事件循环,若你的数据库连接依赖全局事件循环,需调整DataBase类实现以适配;
  • 两种方案都要保证database.get_user_id_by_api_key(api_key)返回可JSON序列化的类型(如字符串、整数),若返回自定义对象仍会触发序列化错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 22:31:00