apppublic/aidocs/httpclient.md
2025-10-05 11:23:33 +08:00

11 KiB
Raw Blame History

HttpClientJsonHttpAPI 技术文档


概述

本文档介绍了一个基于 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, jdJSON 数据)、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: 响应数据的输出模板。
流程:
  1. 合并 envns 得到上下文。
  2. 渲染各个模板headers/params/data
  3. 发起流式请求。
  4. 分块处理响应,可结合 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 集成。
  • 黑名单域名持久化,避免重复探测。

已知问题 / 改进建议

  1. Bugstream_funcchuck 拼写错误

    d = self.chunk_buffer + chuck  # 应为 chunk
    
  2. jd 参数未正确使用

    • make_request 中设置了 hp['jd'] = jd,但 aiohttp.request() 不识别 jd
    • 应改为 hp['json'] = jd
  3. datatmpl 中 multipart 注释未启用

    • 当前行被注释,导致无法上传文件。
    • 如需支持 form-data应取消注释并修复逻辑。
  4. chunk_handle 接口设计模糊

    • 当前仅作占位,建议明确其用途(如过滤、转换、拼接等)。
  5. 安全性考虑

    • unsafe=True 的 CookieJar 可能带来安全风险,建议限制作用域。
    • 模板渲染可能引入注入风险,建议对输入做校验。
  6. 日志级别使用建议

    • info(f'{headers=}...') 输出敏感信息(如 token建议降级为 debug

总结

本模块是一个功能完整的异步 HTTP 客户端解决方案,特别适用于以下场景:

  • 需要通过 SOCKS5 代理访问受限资源。
  • 面向多个 JSON API 的自动化集成。
  • 支持流式响应(如聊天机器人、事件流)。
  • 具备一定的容错和自适应能力。

配合模板引擎,可以实现高度可配置的 API 调用系统,适合作为微服务网关、爬虫框架或自动化测试工具的基础组件。


版本信息

  • 作者:未知
  • 最后修改时间:根据代码推断为近期开发
  • 兼容性Python 3.7+

建议增加版本号字段和单元测试覆盖。


文档完成