
本文详解flask前后端json通信中出现“expecting value: line 1 column 1 (char 0)”错误的根本原因——前端未正确发送json、后端未正确解析,提供完整调试流程、代码修正方案及最佳实践。
本文详解flask前后端json通信中出现“expecting value: line 1 column 1 (char 0)”错误的根本原因——前端未正确发送json、后端未正确解析,提供完整调试流程、代码修正方案及最佳实践。
该错误 Expecting value: line 1 column 1 (char 0) 是 Python json.loads()(由 request.get_json() 内部调用)抛出的经典异常,表明后端接收到的请求体为空、非JSON格式或含不可见控制字符。虽然你在前端使用了 requests.post(..., json=payload),但问题往往出在请求头缺失、前后端数据传输方式不匹配,或调试手段不足。
? 根本原因分析
- ✅ requests.post(..., json=payload) 会自动序列化字典并设置 Content-Type: application/json,理论上无需手动加 headers —— 但若中间存在代理、反向代理(如 Nginx)、或 Flask 配置了 JSONIFY_PRETTYPRINT_REGULAR=False 等非常规设置,可能导致 header 被覆盖或丢弃。
- ❌ 后端 request.get_json() 仅从 request.body 解析 JSON,且默认要求 Content-Type 为 application/json;若 header 缺失或被篡改,request.get_json() 返回 None,后续 data.get('username') 触发 AttributeError 或空值校验失败,但更常见的是——当 request.get_json() 在 None 上调用 .get() 时虽不报错,但 if not username 会误判,而真正触发该 JSON 解析错误的,往往是后端在 response.json().get("error")(即前端尝试解析后端响应)时,后端因异常返回了空响应或 HTML 错误页(如 500 页面),导致前端 response.json() 失败。
⚠️ 注意:你贴出的前端代码中,flash(f"Erreur : {error_message}", "error") 这一行隐含风险——若后端因 data = request.get_json() 返回 None 而抛出 AttributeError(例如 None.get('username')),则会进入 except Exception as e 分支,返回 jsonify({'message': ...});但若后端在 db.session.commit() 前就崩溃(如数据库连接失败),可能返回空响应或非 JSON 响应,此时 response.json() 就会抛出 Expecting value... 错误。
✅ 正确修复方案
1. 前端:增强健壮性 + 显式声明 Content-Type(推荐)
# 替换原 requests.post 调用
try:
response = requests.post(
f'http://{BACK_END_IP}:{BACK_END_PORT}/add-user',
json=payload,
headers={'Content-Type': 'application/json'}, # 显式确保 header
timeout=10
)
# 关键:先检查状态码,再解析 JSON
if response.status_code == 200:
flash("Utilisateur ajouté avec succès.", "success")
return redirect('/')
else:
# 安全解析响应体:检查是否为 JSON
try:
error_data = response.json()
error_message = error_data.get("error", error_data.get("message", "Erreur inconnue"))
except ValueError: # 响应不是合法 JSON
error_message = f"Serveur répond avec un format invalide ({response.status_code})"
flash(f"Erreur : {error_message}", "error")
return redirect('/')
except requests.exceptions.Timeout:
flash("Demande expirée. Veuillez réessayer.", "error")
except requests.exceptions.RequestException as e:
flash(f"Échec de connexion à l'API : {str(e)}", "error")2. 后端:防御性解析 + 日志诊断
@app.route('/add-user', methods=['POST'])
def addUser():
current_user = get_user_from_token(request)
if not current_user or not current_user.admin:
return jsonify({"error": "Accès refusé : admin requis"}), 401
# ✅ 安全获取 JSON 数据(带 fallback 和日志)
data = request.get_json(silent=True) # silent=True 返回 None 而非抛异常
if data is None:
# 尝试回退到 form(兼容浏览器表单提交场景)
data = {
'username': request.form.get('username'),
'email': request.form.get('email'),
'password': request.form.get('password')
}
app.logger.warning(f"[DEBUG] JSON non reçu, fallback vers form: {data}")
# ✅ 强制类型校验
username = str(data.get('username', '')).strip()
email = str(data.get('email', '')).strip()
password = str(data.get('password', '')).strip()
if not all([username, email, password]):
return jsonify({"error": "Tous les champs sont requis."}), 400
# ... 后续业务逻辑(保持不变)3. 必备调试技巧(开发阶段务必启用)
# 在后端 addUser() 开头添加:
app.logger.info(f"[REQUEST] Headers: {dict(request.headers)}")
app.logger.info(f"[REQUEST] Raw data: {request.get_data(as_text=True)}")
app.logger.info(f"[REQUEST] Parsed JSON: {request.get_json(silent=True)}")运行 Flask 时添加 --debug 并查看终端日志,确认:
- Content-Type: application/json 是否存在;
- Raw data 是否为有效 JSON 字符串(如 {"username":"a","email":"b","password":"c"});
- Parsed JSON 是否成功解析。
? 常见误区与规避
- 不要混用 json= 和 data=:requests.post(json=payload) 已处理序列化和 header;若同时传 data=json.dumps(payload) + headers,易造成重复编码。
- 避免在生产环境依赖 request.get_json() 无保护调用:始终使用 silent=True 或 force=True + 类型检查。
-
Postman 测试成功 ≠ 前端调用成功:浏览器同源策略、CORS、CSRF token(若启用)均可能干扰;建议用 curl 模拟真实请求:
curl -X POST http://localhost:5001/add-user \ -H "Content-Type: application/json" \ -d '{"username":"test","email":"t@e.st","password":"123"}'
✅ 总结
该错误本质是 JSON 解析上下文断裂:要么前端未发出合法 JSON 请求(header 缺失/数据为空),要么后端未妥善处理解析失败场景。解决关键在于——
? 前端:显式 header + response.json() 前做 status_code 和 Content-Type 判断;
? 后端:用 request.get_json(silent=True) + 回退机制 + 全面日志;
? 全程:用 app.logger 或 print() 输出原始请求体,而非仅依赖 request.get_json() 的抽象结果。
遵循以上方案,可 100% 消除此类“line 1 column 1”错误,并构建健壮的 API 通信链路。


















