在软件开发与测试流程中,高效、准确地进行接口测试是保障后端服务质量的关键环节。除了使用Postman、JMeter等图形化工具,我们也可以借助代码实现更灵活、可编程的自动化测试。Python 的 requests 库因其简洁易用而广受欢迎,是进行HTTP接口测试的得力助手。而对于更复杂的场景,如拦截并修改HTTP响应,mitmproxy 则提供了强大的代理能力。
本文将介绍如何组合使用 requests 和 mitmproxy,从基础的接口请求到高级的响应拦截,构建自动化的接口测试方案。
使用 requests 进行基础 HTTP 接口测试
requests 库几乎涵盖了所有常见的HTTP操作,其设计遵循 HTTP 协议标准,使用起来直观明了。
发送 GET 与 POST 请求
最基本的GET和POST请求可以通过几行代码完成:
import requests
# 发送一个简单的GET请求
response = requests.get('https://api.example.com/data')
print(response.status_code) # 打印状态码,如200
print(response.json()) # 如果响应是JSON,直接解析
# 发送一个带JSON数据的POST请求
payload = {'key1': 'value1', 'key2': 'value2'}
headers = {'Content-Type': 'application/json'}
response = requests.post('https://api.example.com/submit', json=payload, headers=headers)
print(response.text) # 打印原始响应文本
处理请求参数、头部与超时
在实际测试中,我们通常需要更精细地控制请求。
import requests
# 1. 查询参数 (GET)
params = {'search': 'keyword', 'page': 1}
r = requests.get('https://api.example.com/search', params=params)
# 2. 表单数据 (POST)
form_data = {'username': 'test', 'password': 'secret'}
r = requests.post('https://api.example.com/login', data=form_data)
# 3. 自定义请求头
headers = {
'User-Agent': 'My-Test-Script/1.0',
'Authorization': 'Bearer your_token_here'
}
r = requests.get('https://api.example.com/protected', headers=headers)
# 4. 设置超时(连接超时和读取超时)
try:
r = requests.get('https://api.example.com/slow', timeout=(3.05, 27))
except requests.exceptions.Timeout:
print("请求超时!")
会话保持与认证
使用 Session 对象可以自动管理Cookie,在多次请求间保持会话状态,对于测试需要登录的接口非常方便。
import requests
# 创建一个会话
session = requests.Session()
# 登录,会话会自动保存响应的Cookie
login_data = {'user': 'admin', 'pass': 'password'}
session.post('https://api.example.com/login', data=login_data)
# 后续请求无需再处理Cookie,会话会自动携带
profile = session.get('https://api.example.com/profile').json()
print(profile)
# 使用HTTP基本认证
from requests.auth import HTTPBasicAuth
r = requests.get('https://api.example.com/secure',
auth=HTTPBasicAuth('username', 'password'))
进阶:使用 mitmproxy 拦截与修改 HTTP 响应
在某些测试场景下,我们可能需要模拟服务器返回特定数据(如错误状态、异常数据格式)以验证客户端的健壮性。此时,mitmproxy 作为一个中间人代理,可以精准地拦截并篡改经过它的HTTP/HTTPS流量。
编写 mitmproxy 拦截脚本
我们可以编写一个 addon.py 脚本,定义响应拦截的逻辑。以下示例将匹配特定URL的响应,并将其状态码和内容替换为自定义值。
# addon.py
from mitmproxy import http
class MockResponse:
def response(self, flow: http.HTTPFlow) -> None:
# 1. 匹配需要拦截的请求URL
if "api.example.com/target-endpoint" in flow.request.pretty_url:
# 2. 创建模拟的响应
mock_response = http.Response.make(
status_code=500, # 模拟服务器内部错误
content=b'{"error": "Internal Server Error", "code": 500}', # 模拟JSON错误信息
headers={"Content-Type": "application/json"} # 保持头部类型
)
# 3. 用模拟响应替换原始响应
flow.response = mock_response
print(f"[mitmproxy] 已拦截并篡改响应: {flow.request.pretty_url}")
启动 mitmproxy 并加载脚本
首先,在终端启动 mitmproxy,并指定监听端口和加载我们编写的脚本:
mitmproxy -s addon.py -p 8888
此时,mitmproxy 会在本地的 8888 端口启动一个代理服务器。
配置 requests 使用代理
最后,我们需要让 requests 库的请求通过这个代理发出,这样拦截才会生效。
import requests
# 配置代理,指向正在运行的 mitmproxy
proxies = {
'http': 'http://127.0.0.1:8888',
'https': 'http://127.0.0.1:8888', # 注意:mitmproxy 同样使用HTTP代理接管HTTPS
}
# 发送请求,此请求将被 addon.py 中的脚本拦截并修改
response = requests.get('https://api.example.com/target-endpoint', proxies=proxies, verify=False) # verify=False 忽略证书验证(仅测试环境使用)
print(f"状态码: {response.status_code}") # 输出: 500
print(f"响应体: {response.text}") # 输出: {"error": "Internal Server Error", "code": 500}
通过上述组合,我们便实现了一个从简单请求到复杂流量拦截的全链路接口测试能力。requests 负责构造和发送请求,而 mitmproxy 则提供了在网络层修改服务器响应的可能,非常适合进行边界条件、异常流和前后端联调测试。