11 KiB
HttpClient 与 JsonHttpAPI 技术文档
概述
本文档介绍了一个基于 aiohttp 的异步 HTTP 客户端库,包含两个核心类:
HttpClient:提供灵活、可配置的异步 HTTP 请求功能,支持代理(SOCKS5)、自动重试、Cookie 管理、域名黑名单缓存等。JsonHttpAPI:构建在HttpClient上的高级接口,用于处理 JSON 格式的 API 调用,支持模板渲染、流式响应处理和动态参数注入。
该模块适用于需要高并发访问 Web 接口、支持代理切换、具备容错机制的应用场景。
依赖项
aiohttp
aiohttp_socks
certifi
ssl
asyncio
urllib.parse
json
re
traceback
os
appPublic.myTE (自定义模板引擎)
appPublic.log (日志模块)
注意:
appPublic.*是项目内部工具模块,请确保已安装或替换为对应实现。
全局常量
| 常量 | 值 | 含义 |
|---|---|---|
RESPONSE_BIN |
0 |
返回二进制数据(bytes) |
RESPONSE_TEXT |
1 |
返回文本字符串(使用编码解码) |
RESPONSE_JSON |
2 |
返回解析后的 JSON 对象 |
RESPONSE_FILE |
3 |
预留,表示文件下载(当前未使用) |
RESPONSE_STREAM |
4 |
流式传输模式(通过 __call__ 实现) |
工具函数
get_domain(url: str) -> str
从 URL 中提取域名(主机名),若 URL 不带协议则默认补全为 http://。
参数:
url(str): 输入的 URL 字符串。
返回值:
str: 提取出的域名部分(不包含端口和路径)。
示例:
get_domain("https://example.com:8080/path") → "example.com"
get_domain("example.org") → "example.org" (自动补全 http)
异常类
HttpError(code, msg)
继承自 Exception,表示 HTTP 请求失败时的错误。
属性:
code(int): HTTP 状态码。msg(str): 错误描述信息。
方法:
__str__(): 返回格式化错误信息"Error Code:{code}, {msg}"。__expr__(): 同__str__(),兼容调试输出。
核心类:HttpClient
一个异步 HTTP 客户端,支持 SOCKS5 代理、自动故障转移、Cookie 管理及域名黑名单持久化。
初始化:__init__(coding='utf-8', socks5_proxy_url=None)
参数:
coding(str): 文本响应的字符编码,默认'utf-8'。socks5_proxy_url(str or None): 可选的 SOCKS5 代理地址,如'socks5://localhost:1086'。
内部状态:
session:aiohttp.ClientSession实例(延迟初始化)。cookies: 存储各域名 Cookie 的字典。proxy_connector: 当前使用的代理连接器。blocked_domains: 被标记为无法直连需走代理的域名集合(从.proxytarget文件加载)。load_cache(): 自动加载本地缓存的被屏蔽域名列表。
方法说明
save_cache()
将当前 blocked_domains 集合保存到用户主目录下的 ~/.proxytarget 文件中,每行一个域名。
load_cache()
从 ~/.proxytarget 加载被屏蔽域名。如果文件不存在,则创建空文件。
close()
关闭当前会话(释放资源),协程方法。
setCookie(url, cookies)
根据 URL 设置对应域名的 Cookie。
getCookies(url)
获取指定 URL 所属域名的 Cookies。
getsession(url)
懒加载并返回 ClientSession 实例,启用 unsafe=True 的 CookieJar 以接受任意域的 Cookie。
response_generator(url, resp)
生成器函数,逐块返回响应内容(每次最多 1024 字节),同时更新 Cookie。
response_handle(url, resp, resp_type, stream_func)
根据 resp_type 类型处理响应体,并可选地调用 stream_func 处理流式数据。
resp_type |
行为 |
|---|---|
RESPONSE_BIN |
await resp.read() |
RESPONSE_TEXT |
await resp.text(encoding) |
RESPONSE_JSON |
await resp.json() |
其他 / None |
忽略 |
若提供了 stream_func,则以 chunk 方式流式传递数据。
grapCookie(url)
从当前 Session 的 CookieJar 中提取特定域名的所有 Cookie。
make_request(...)
底层请求构造函数,支持 GET/POST 等方法,允许传入 params, data, jd(JSON 数据)、headers。
参数:
url: 请求地址。method: HTTP 方法(GET、POST 等)。params: 查询参数(dict)。data: 表单数据(bytes 或 dict)。jd: JSON 数据(会被设置为json=参数)。headers: 请求头。use_proxy: 是否使用 SOCKS5 代理。
若是 HTTPS 请求,自动添加由
certifi提供的 CA 证书上下文。
get_request_response(...)
智能路由请求:先尝试直连;若失败且存在代理配置,则记录失败域名并改用代理重试。
特性:
- 自动检测是否应绕过代理(不在
blocked_domains中)。 - 第一次请求失败后,将域名加入
blocked_domains并持久化。 - 支持异常捕获与日志输出。
request(...)
高层封装,发送请求并按 response_type 解析结果。
参数:
response_type: 控制返回类型(见全局常量)。stream_func: 可选的异步回调函数,用于处理流式数据块。- 其余同
make_request。
返回:
- 成功时返回相应类型的响应数据。
- 失败时抛出
HttpError。
__call__(...)
支持 async for 的流式调用方式,适合大文件下载或 Server-Sent Events 场景。
示例:
async for chunk in hc('https://example.com/stream'):
print(chunk)
get(url, **kw) 和 post(url, **kw)
便捷方法,分别发起 GET 和 POST 请求。
高级类:JsonHttpAPI
专为调用 RESTful JSON API 设计的模板驱动客户端。
初始化:__init__(env={}, socks5_proxy_url=None)
参数:
env(dict): 全局变量环境,供模板渲染使用。socks5_proxy_url(str): 传递给底层HttpClient的代理设置。
内部组件:
te: 使用MyTemplateEngine进行模板渲染。hc: 实例化的HttpClient。
方法说明
stream_func(chunk)
内部流处理器,用于处理换行分隔的 JSON 流(如 SSE)。注意:代码中有拼写错误 chuck 应为 chunk。
⚠️ Bug 提示:原代码中
d = self.chunk_buffer + chuck应改为chunk。
功能包括:
- 缓冲数据并按
\n分割。 - 尝试解析每条 JSON 消息。
- 使用
resptmpl渲染响应。 - 调用用户提供的
user_stream_func回调。
chunk_handle(chunk, lead, end)
钩子函数,可用于预处理每个数据块(例如去除前缀、添加结束标记)。默认直接返回原块。
__call__(...)
异步生成器接口,支持流式 API 调用。
参数:
url: API 地址。method: 请求方法。ns: 当前命名空间变量(优先级高于env)。headerstmpl: 请求头的 JSON 模板(字符串形式的 JSON + 模板语法)。paramstmpl: 查询参数模板。datatmpl: 请求体模板(JSON 字符串含变量)。chunk_leading,chunk_end: 分块控制标记。resptmpl: 响应数据的输出模板。
流程:
- 合并
env与ns得到上下文。 - 渲染各个模板(headers/params/data)。
- 发起流式请求。
- 分块处理响应,可结合
resptmpl动态转换输出。
输出:
yield经过处理和模板渲染后的每一“段”数据。
call(...)
同步风格的调用入口(实际仍是 await 协程),支持非流式和流式两种模式。
参数:
stream_func: 用户自定义流处理函数(接收 JSON 对象)。- 其他同
__call__。
返回:
- 若无
resptmpl:原始 JSON 响应。 - 若有
resptmpl:经模板渲染后再反序列化的 JSON 结果。
使用示例
1. 基础请求(主程序测试)
async def main():
hc = HttpClient(socks5_proxy_url='socks5://localhost:1086')
# 流式读取百度首页
async for d in hc('https://www.baidu.com'):
print(d)
# 获取 Google 主页文本
r = await hc.request('https://www.google.com')
print(r)
await hc.close()
if __name__ == '__main__':
loop = asyncio.new_event_loop()
loop.run_until_complete(main())
2. 使用 JsonHttpAPI 调用模板化 API
api = JsonHttpAPI(env={'token': 'abc123'}, socks5_proxy_url='socks5://127.0.0.1:1086')
# 定义模板
headers_tmpl = '{"Authorization": "Bearer {{token}}"}'
params_tmpl = '{"page": "{{page}}"}'
async def on_chunk(data):
print("Received:", data)
result = await api.call(
url="https://api.example.com/data",
method="GET",
ns={"page": 1},
headerstmpl=headers_tmpl,
paramstmpl=params_tmpl,
stream_func=on_chunk
)
注意事项与建议
✅ 优点
- 支持异步高并发。
- 内建代理自动切换机制。
- Cookie 自动管理。
- 模板化请求构建,适合复杂 API 集成。
- 黑名单域名持久化,避免重复探测。
❗ 已知问题 / 改进建议
-
Bug:
stream_func中chuck拼写错误d = self.chunk_buffer + chuck # 应为 chunk -
jd参数未正确使用- 在
make_request中设置了hp['jd'] = jd,但aiohttp.request()不识别jd。 - 应改为
hp['json'] = jd。
- 在
-
datatmpl中 multipart 注释未启用- 当前行被注释,导致无法上传文件。
- 如需支持 form-data,应取消注释并修复逻辑。
-
chunk_handle接口设计模糊- 当前仅作占位,建议明确其用途(如过滤、转换、拼接等)。
-
安全性考虑
unsafe=True的 CookieJar 可能带来安全风险,建议限制作用域。- 模板渲染可能引入注入风险,建议对输入做校验。
-
日志级别使用建议
info(f'{headers=}...')输出敏感信息(如 token),建议降级为debug。
总结
本模块是一个功能完整的异步 HTTP 客户端解决方案,特别适用于以下场景:
- 需要通过 SOCKS5 代理访问受限资源。
- 面向多个 JSON API 的自动化集成。
- 支持流式响应(如聊天机器人、事件流)。
- 具备一定的容错和自适应能力。
配合模板引擎,可以实现高度可配置的 API 调用系统,适合作为微服务网关、爬虫框架或自动化测试工具的基础组件。
版本信息
- 作者:未知
- 最后修改时间:根据代码推断为近期开发
- 兼容性:Python 3.7+
建议增加版本号字段和单元测试覆盖。
✅ 文档完成