1. 问题现象与背景解析
最近在调试Python的POST请求时遇到了一个典型的JSON解析错误:"JSON parse error: Unrecognized token 'pageNo': was expecting...",特别是在请求参数中包含中文字符时问题更加明显。这种错误在API开发中相当常见,但背后涉及字符编码、HTTP协议规范、JSON序列化等多个技术点的交叉影响。
问题的典型表现是:当使用requests库发送POST请求,且请求体中包含中文参数时,服务端返回400 Bad Request,并提示无法解析JSON体。更诡异的是,同样的请求参数,在Postman等工具中却能正常执行。这种差异往往让开发者陷入困惑。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心问题诊断与原理分析
2.1 JSON规范与字符编码要求
JSON标准(RFC 8259)明确规定:
- JSON文本必须使用Unicode编码(默认UTF-8)
- 所有字符串必须使用双引号(")包裹
- 控制字符必须转义
当服务端收到请求时,会严格按照这些规范校验请求体。如果请求头中的Content-Type未正确声明字符编码,或者请求体实际编码与声明不符,就会导致解析失败。
2.2 Python requests库的默认行为
requests库在发送POST请求时:
- 对于dict类型的data参数,默认会form-encode为application/x-www-form-urlencoded
- 对于dict类型的json参数,会序列化为JSON字符串并使用application/json
- 默认使用UTF-8编码,但需要显式设置headers才能确保服务端正确识别
2.3 常见错误模式分析
错误示例代码:
python复制import requests
data = {
'pageNo': 1,
'keyword': '搜索词'
}
response = requests.post('http://api.example.com', data=data)
这里存在三个潜在问题:
- 使用data参数而非json参数,导致数据被form-encoded
- 未设置Content-Type头
- 中文未做URL编码
3. 完整解决方案与最佳实践
3.1 标准JSON请求实现
修正后的代码:
python复制import requests
import json
url = 'http://api.example.com'
headers = {
'Content-Type': 'application/json; charset=utf-8'
}
data = {
'pageNo': 1,
'keyword': '搜索词'
}
response = requests.post(
url,
json=data, # 自动序列化为JSON
headers=headers
)
关键改进点:
- 使用json参数而非data参数
- 显式设置Content-Type头
- 让requests处理JSON序列化
3.2 处理复杂场景的进阶方案
当需要自定义JSON序列化时:
python复制import json
from requests.structures import CaseInsensitiveDict
custom_data = {
'page': {'no': 1, 'size': 20},
'filter': {'name': '测试', 'date': '2023-01-01'}
}
headers = CaseInsensitiveDict({
'Content-Type': 'application/json',
'Accept-Charset': 'utf-8'
})
response = requests.post(
