如何解决Python requests库json方法返回None的问题?

问题现象与根源分析

当开发者使用Python的requests库处理API响应时,response.json()方法意外返回None是高频问题。这种现象通常源于以下技术原因:

  • HTTP响应体为空:服务器返回204 No Content状态码时,响应体长度为0
  • Content-Type不匹配:响应头未声明application/json但实际返回JSON
  • 字符编码冲突:响应体使用非UTF-8编码导致解析失败
  • 无效JSON格式:响应包含未转义控制字符或尾随逗号
  • 中间件干扰:代理服务器或CDN修改了原始响应

五种诊断与解决方案

1. 验证响应状态与内容

import requests

resp = requests.get('https://api.example.com/data')
print(resp.status_code)  # 确认状态码
print(resp.content)      # 检查原始字节内容
print(resp.headers)      # 验证Content-Type

2. 强制编码处理

当响应头未指定编码时,可显式设置解码方式:

json_data = resp.json(encoding='ISO-8859-1')  # 常见备选编码

3. 使用原始文本解析

通过json模块进行二次解析:

import json
try:
    data = json.loads(resp.text)
except json.JSONDecodeError as e:
    print(f"解析失败: {e.msg}")

4. 异常捕获策略

复合异常处理方案:

try:
    data = resp.json() or {}
except (ValueError, requests.exceptions.JSONDecodeError):
    data = parse_fallback(resp.text)

5. 调试中间件影响

使用curl -v对比直接请求与Python请求的原始响应差异,排查:

  • gzip压缩问题
  • Transfer-Encoding分块
  • HTTP重定向丢失头信息

深度技术细节

当JSON解析失败时,requests库的底层逻辑会:

  1. 检查Content-Type包含json子串
  2. 调用response.encoding进行解码
  3. 使用simplejson或标准库json模块解析
  4. 静默处理所有异常并返回None

建议通过hooks机制添加预处理:

def check_json(resp, *args, **kwargs):
    if not resp.ok or not resp.content:
        resp._content = b'{}'

session = requests.Session()
session.hooks['response'].append(check_json)