Flask RESTful Put接口JSON解码错误排查求助
解决Flask-RESTful中PUT请求的JSONDecodeError问题
问题原因分析
你遇到的requests.exceptions.JSONDecodeError本质是服务器返回的响应不是有效的JSON格式,主要有三个核心原因:
- 数据库表未初始化:代码未创建SQLite数据库表,首次运行插入数据时触发服务器500错误,返回HTML错误页面而非JSON。
- abort用法不规范:直接使用
abort(message='xxx')会返回默认的500错误HTML页面,而非Flask-RESTful规范的JSON错误响应。 - 请求数据格式不符合RESTful规范:
requests.put默认用表单格式发送数据,虽能被解析,但更规范的REST请求应使用JSON格式。
解决方案
1. 初始化数据库表
在main.py的启动逻辑中添加表创建代码,确保首次运行自动生成数据库表:
if __name__ == "__main__": with app.app_context(): db.create_all() # 创建所有模型对应的数据库表 app.run(debug=True)
2. 修正abort的用法
给abort指定正确的HTTP状态码,让Flask-RESTful返回JSON格式的错误响应:
# get方法中修改abort逻辑 if not result: abort(404, message='could not find the video with that id') # put方法中修改abort逻辑 if result: abort(409, message='video id taken')
3. 规范客户端请求格式
在test.py中使用json参数发送请求,确保数据以JSON格式传递:
response = requests.put( BASE + f'video/{32}', json={"likes": 10353, 'name': 'studywithme for 2 hours', 'views': 12342000} )
修改后的完整代码
main.py
from flask import Flask, request from flask_restful import Api, Resource, reqparse, abort, fields, marshal_with from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) api = Api(app) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db' db = SQLAlchemy(app) class VideoModel(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) views = db.Column(db.Integer, nullable=False) likes = db.Column(db.Integer, nullable=False) def __repr__(self): return f'Video(name = {self.name},views = {self.views}, likes = {self.likes})' video_put_args = reqparse.RequestParser() video_put_args.add_argument( 'name', type=str, help='name of the video is required', required=True) video_put_args.add_argument( 'views', type=int, help='views on the video is required', required=True) video_put_args.add_argument( 'likes', type=int, help='likes on the video is required', required=True) resource_fields = {'id': fields.Integer, 'name': fields.String, 'views': fields.Integer, 'likes': fields.Integer} class Video(Resource): @marshal_with(resource_fields) def get(self, video_id): result = VideoModel.query.filter_by(id=video_id).first() if not result: abort(404, message='could not find the video with that id') return result @marshal_with(resource_fields) def put(self, video_id): args = video_put_args.parse_args() result = VideoModel.query.filter_by(id=video_id).first() if result: abort(409, message='video id taken') video = VideoModel( id=video_id, name=args['name'], views=args['views'], likes=args['likes']) db.session.add(video) db.session.commit() return video api.add_resource(Video, "/video/<int:video_id>") if __name__ == "__main__": with app.app_context(): db.create_all() app.run(debug=True)
test.py
import requests BASE = "http://127.0.0.1:5000/" response = requests.put( BASE + f'video/{32}', json={"likes": 10353, 'name': 'studywithme for 2 hours', 'views': 12342000} ) print(response.json())
修改完成后,服务器会返回标准JSON响应,客户端可正常解析response.json()获取结果。
内容的提问来源于stack exchange,提问作者Studywith Me
相关产品推荐
相关产品推荐

