3行代码搞定响应重写:Requests高级技巧让API数据改造更简单
【免费下载链接】requests 项目地址: https://gitcode.com/gh_mirrors/req/requests
你是否遇到过这些尴尬场景?调用第三方API时返回格式不符合系统要求,想隐藏敏感响应头却无能为力,调试时需要临时替换接口返回值?不用再手动解析和重构响应数据了!本文将带你掌握Requests库的响应重写技术,通过简单几步实现响应内容与头信息的灵活修改,让API数据处理变得优雅高效。
为什么需要响应重写?
在日常开发中,我们经常需要对API返回的响应进行二次处理:
- 数据格式转换:将XML响应转为JSON,或调整字段结构
- 敏感信息过滤:移除响应中的用户密码、手机号等敏感数据
- 调试与测试:模拟不同响应结果,验证系统容错能力
- 兼容性处理:统一不同API的返回格式,减少前端适配成本
传统的做法是在请求后编写大量解析和重构代码,不仅冗余繁琐,还容易出错。Requests的响应重写机制可以将这些处理逻辑与主流程解耦,让代码更简洁、更易于维护。
响应重写的两种实现方式
Requests提供了两种主要方式来修改响应内容:事件钩子(Hooks) 和Prepared Request。前者适合全局统一处理,后者适用于单请求的精细控制。
方式一:使用响应钩子(Hooks)
事件钩子是Requests最优雅的响应处理方式,通过注册钩子函数,可以在每个响应返回时自动执行自定义逻辑。核心原理是利用hooks参数注册response事件处理器,在钩子函数中修改响应对象并返回。
实现步骤非常简单:
- 定义钩子函数,接收响应对象并返回修改后的对象
- 在请求时通过
hooks参数注册该函数
import requests
def rewrite_response(r, *args, **kwargs):
# 修改响应内容
r._content = b'{"status": "success", "data": "modified"}'
# 修改响应头
r.headers['X-Custom-Header'] = 'modified-by-hook'
return r
# 注册钩子并发送请求
response = requests.get(
'https://httpbin.org/get',
hooks={'response': rewrite_response}
)
print(response.json()) # 输出: {'status': 'success', 'data': 'modified'}
print(response.headers['X-Custom-Header']) # 输出: modified-by-hook
钩子函数的核心代码在src/requests/hooks.py中实现,通过dispatch_hook函数调度执行所有注册的钩子。钩子函数可以修改响应的几乎所有属性,包括内容、状态码、头信息等。
方式二:使用Prepared Request
对于需要更精细控制的场景,可以使用Prepared Request。这种方式允许你在发送请求前准备好请求对象,发送后直接修改原始响应数据。
实现步骤如下:
- 创建Request对象并准备为PreparedRequest
- 发送请求获取响应
- 直接修改响应对象的属性
from requests import Request, Session
s = Session()
req = Request('GET', 'https://httpbin.org/get')
prepped = s.prepare_request(req)
# 发送请求并获取响应
response = s.send(prepped)
# 直接修改响应内容
response._content = b'{"result": "manually modified content"}'
# 修改响应头
response.headers['Server'] = 'Custom-Server'
print(response.json()) # 输出: {'result': 'manually modified content'}
print(response.headers['Server']) # 输出: Custom-Server
响应对象的定义在src/requests/models.py中,其中_content属性存储原始响应内容,headers属性是一个CaseInsensitiveDict对象,支持大小写不敏感的键访问。
实战案例:打造API响应转换器
让我们通过一个完整案例,实现一个能够同时修改响应内容和头信息的API响应转换器。这个转换器将实现:移除敏感字段、转换日期格式、添加自定义响应头。
import json
from datetime import datetime
import requests
from requests.models import Response
def convert_date_format(date_str):
"""将ISO格式日期转换为自定义格式"""
try:
dt = datetime.fromisoformat(date_str.replace('Z', '+00:00'))
return dt.strftime('%Y-%m-%d %H:%M:%S')
except ValueError:
return date_str
def api_response_transformer(r, *args, **kwargs):
"""API响应转换器钩子函数"""
# 1. 修改响应头
r.headers['X-Transformed'] = 'true'
r.headers['X-Transform-Time'] = datetime.now().isoformat()
# 2. 处理响应内容
if r.headers.get('Content-Type') == 'application/json':
try:
data = r.json()
# 移除敏感字段
sensitive_fields = ['password', 'token', 'credit_card']
for field in sensitive_fields:
data.pop(field, None)
# 转换日期格式
if 'created_at' in data:
data['created_at'] = convert_date_format(data['created_at'])
# 添加自定义字段
data['transformed'] = True
# 将修改后的数据转换回JSON字符串
r._content = json.dumps(data).encode('utf-8')
except (json.JSONDecodeError, TypeError):
# 如果不是有效的JSON,不做处理
pass
return r
# 使用转换器发送请求
response = requests.get(
'https://httpbin.org/json',
hooks={'response': api_response_transformer}
)
print("响应头:", response.headers['X-Transformed']) # 输出: true
print("转换后内容:", response.json())
这个案例展示了如何利用钩子函数实现复杂的响应转换逻辑。通过这种方式,我们可以将所有响应处理逻辑集中在一个函数中,使主代码保持简洁清晰。
高级技巧与最佳实践
全局响应重写
如果需要对所有请求应用相同的响应处理逻辑,可以使用Session对象注册全局钩子:
import requests
def global_response_hook(r, *args, **kwargs):
# 添加全局响应头
r.headers['X-Global-Hook'] = 'active'
return r
# 创建会话并注册全局钩子
session = requests.Session()
session.hooks['response'].append(global_response_hook)
# 所有通过该会话发送的请求都会应用钩子
response1 = session.get('https://httpbin.org/get')
response2 = session.get('https://httpbin.org/headers')
print(response1.headers['X-Global-Hook']) # 输出: active
print(response2.headers['X-Global-Hook']) # 输出: active
条件性响应修改
根据不同的响应状态码或内容进行条件性修改:
def conditional_rewriter(r, *args, **kwargs):
# 只处理404响应
if r.status_code == 404:
r._content = b'{"error": "资源不存在", "code": 404, "message": "请检查请求URL是否正确"}'
r.headers['Content-Type'] = 'application/json'
# 为成功响应添加处理时间
elif r.status_code == 200 and r.headers.get('Content-Type') == 'application/json':
try:
data = r.json()
data['processing_time_ms'] = r.elapsed.microseconds // 1000
r._content = json.dumps(data).encode('utf-8')
except json.JSONDecodeError:
pass
return r
注意事项
- 性能考虑:复杂的响应处理可能会影响性能,特别是对于大型响应体
- 错误处理:确保钩子函数中有完善的异常处理,避免影响主流程
- 调试技巧:使用
print或日志记录跟踪钩子执行过程,方便调试 - 版本兼容性:直接修改
_content等私有属性可能会随Requests版本变化而失效,建议优先使用官方API
总结
通过本文的介绍,你已经掌握了使用Requests进行响应重写的核心技术。无论是简单的响应头修改,还是复杂的内容转换,都可以通过钩子函数或Prepared Request轻松实现。这些技巧能够帮助你更优雅地处理API响应,减少冗余代码,提高开发效率。
响应重写技术只是Requests强大功能的冰山一角,更多高级用法等着你去探索。建议深入阅读官方文档中的高级用法章节,解锁更多Requests技巧。
最后,记住响应重写应该用于合理的场景,遵守API使用规范,不要滥用这项技术进行恶意数据篡改或绕过安全限制。
你在项目中遇到过哪些需要修改API响应的场景?又是如何解决的?欢迎在评论区分享你的经验和技巧!
【免费下载链接】requests 项目地址: https://gitcode.com/gh_mirrors/req/requests
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考





