本文详解 flask 中因缺失 content-type: application/json 请求头导致 request.get_json() 返回 none 的典型问题,并提供完整可运行的修复方案、客户端调用示例及关键注意事项。
本文详解 flask 中因缺失 content-type: application/json 请求头导致 request.get_json() 返回 none 的典型问题,并提供完整可运行的修复方案、客户端调用示例及关键注意事项。
在使用 Flask 构建 RESTful API 时,若后端通过 request.get_json() 解析客户端提交的 JSON 数据,但始终返回 None 或触发 Did not attempt to load JSON data because the request Content-Type was not 'application/json' 警告,根本原因在于:Flask 默认仅在请求头明确声明 Content-Type: application/json 时,才尝试解析请求体为 JSON 对象。即使你使用 requests.post(..., json=...),它虽会自动序列化数据并设置 Content-Type,但在某些调试场景(如手动构造请求、前端 fetch 未设 header、或中间代理覆盖)下该头可能丢失。
以下是一个修复后的完整服务端示例(含健壮性增强):
from flask import Flask, jsonify, request
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
class Main(Resource):
def get(self):
# 示例:模拟从数据库获取电影数据
movie_data_list = [
{"id": 1, "title": "加勒比海盗", "actor": "约翰尼·德普"},
{"id": 2, "title": "剪刀手爱德华", "actor": "约翰尼·德普"},
{"id": 3, "title": "查理和巧克力工厂", "actor": "约翰尼·德普"}
]
return jsonify({"movies": movie_data_list})
def post(self):
# 关键:显式指定 force=True 可绕过 Content-Type 检查(仅用于调试/兼容场景)
# 更推荐方式:确保客户端发送正确 header(见下方说明)
data_from_client = request.get_json(silent=True) # silent=True 避免 400 错误
if data_from_client is None:
return jsonify({
"error": "Invalid JSON payload or missing Content-Type: application/json header"
}), 400
# ✅ 安全处理:验证必需字段
query = data_from_client.get("name")
if not isinstance(query, str) or not query.strip():
return jsonify({"error": "Missing or invalid 'name' field"}), 400
# 此处可接入 LLM 调用、数据库查询等业务逻辑
# 示例响应(实际应替换为 GPT 处理 + DatabaseData 查询)
response = {
"query": query,
"suggested_movies": [
{"title": "加勒比海盗:黑珍珠号的诅咒", "year": 2003},
{"title": "爱德华剪刀手", "year": 1990},
{"title": "理发师陶德", "year": 2007}
],
"status": "success"
}
return jsonify(response)
api.add_resource(Main, "/movie_gpt_ai/back/moviedata")
if __name__ == "__main__":
app.run(debug=True, port=1000, host='localhost')对应客户端调用(Python requests),必须显式设置 Content-Type 头(尽管 json= 参数通常已自动设置,但显式声明更清晰、可调试):
import requests
# ✅ 正确写法:显式声明 headers(推荐)
headers = {"Content-Type": "application/json"}
res = requests.post(
"http://localhost:1000/movie_gpt_ai/back/moviedata",
json={"name": "Три лучших фильма с Джонни Депом"},
headers=headers
)
print("POST Response:", res.json())
# ✅ GET 请求不受影响(无需 Content-Type)
res_get = requests.get("http://localhost:1000/movie_gpt_ai/back/moviedata")
print("GET Response:", res_get.json())⚠️ 重要注意事项:
- requests.post(url, json=...) 默认会自动设置 Content-Type: application/json,因此多数情况下无需手动加 headers。但如果遇到问题,请用抓包工具(如 Wireshark、浏览器 DevTools Network 面板)确认请求头是否真实发出;
- 避免滥用 force=True(如 request.get_json(force=True)),它会强制解析 body 为 JSON,即使 Content-Type 是 text/plain,这会掩盖真实问题,降低接口安全性与可维护性;
- 前端 JavaScript 使用 fetch 时,务必手动设置:
fetch("http://localhost:1000/movie_gpt_ai/back/moviedata", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: "Три лучших фильма с Джонни Депом" }) }) - 生产环境建议添加请求校验(如 marshmallow)、日志记录及错误统一处理中间件,提升鲁棒性。
总结:该问题本质是 HTTP 协议规范与 Flask 设计哲学的体现——内容类型需由客户端明确声明,服务端不猜测。坚持“客户端负责正确声明,服务端负责严格校验”的原则,是构建可靠 API 的基石。










