311 lines
8.3 KiB
Markdown
311 lines
8.3 KiB
Markdown
# HTTP 客户端库技术文档
|
||
|
||
这是一个基于 `requests` 库封装的 Python HTTP 客户端工具类,提供了自动会话管理、异常处理和简化接口调用的功能。适用于需要与 Web API 交互的应用场景。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
- [概述](#概述)
|
||
- [依赖](#依赖)
|
||
- [异常类型](#异常类型)
|
||
- [全局变量](#全局变量)
|
||
- [Http_Client 类](#http_client-类)
|
||
- [`__init__`](#__init__)
|
||
- [`prepped_handler`](#prepped_handler)
|
||
- [`response_handler`](#response_handler)
|
||
- [`url2domain`](#url2domain)
|
||
- [`_webcall`](#_webcall)
|
||
- [`webcall`](#webcall)
|
||
- [`__call__`](#__call__)
|
||
- [HTTP 方法封装](#http-方法封装)
|
||
- `get`
|
||
- `post`
|
||
- `put`
|
||
- `delete`
|
||
- `option`
|
||
- [使用示例](#使用示例)
|
||
|
||
---
|
||
|
||
## 概述
|
||
|
||
`Http_Client` 是一个轻量级的 HTTP 客户端封装类,主要功能包括:
|
||
|
||
- 自动维护每个域名的 `session`(通过 Cookie 中的 `Set-Cookie` 提取并设置)
|
||
- 支持常见的 HTTP 方法(GET、POST、PUT、DELETE、OPTION)
|
||
- 统一处理响应状态码,并抛出相应异常
|
||
- 对 JSON 响应进行解析,提取业务数据(如 `data` 字段)
|
||
|
||
---
|
||
|
||
## 依赖
|
||
|
||
- `requests`:用于底层 HTTP 请求处理
|
||
安装方式:
|
||
```bash
|
||
pip install requests
|
||
```
|
||
|
||
> ⚠️ 注意:该客户端默认禁用了 SSL 验证(`verify=False`),在生产环境中应谨慎使用。
|
||
|
||
---
|
||
|
||
## 异常类型
|
||
|
||
### `NeedLogin`
|
||
当服务器返回 `401 Unauthorized` 时抛出,表示当前请求未登录或认证失败。
|
||
|
||
```python
|
||
raise NeedLogin
|
||
```
|
||
|
||
### `InsufficientPrivilege`
|
||
当服务器返回 `403 Forbidden` 时抛出,表示权限不足。
|
||
|
||
```python
|
||
raise InsufficientPrivilege
|
||
```
|
||
|
||
### `HTTPError`
|
||
当服务器返回非 `200` 状态码时抛出,包含状态码和请求 URL。
|
||
|
||
#### 属性
|
||
| 属性名 | 类型 | 说明 |
|
||
|-------------|--------|------------------|
|
||
| `resp_code` | int | HTTP 响应状态码 |
|
||
| `url` | str | 请求的完整 URL |
|
||
|
||
#### 方法
|
||
- `__str__()` 和 `__expr__()`:返回格式为 `{url}:{resp_code}` 的字符串
|
||
|
||
> ❗注意:`__expr__` 可能是拼写错误,通常应为 `__repr__`。建议修复此方法名为 `__repr__`。
|
||
|
||
---
|
||
|
||
## 全局变量
|
||
|
||
### `hostsessions: dict`
|
||
存储每个域名对应的 session ID(从 `Set-Cookie` 头部提取),键为协议+主机名(例如 `https://api.example.com`),值为 session 字符串。
|
||
|
||
用途:实现跨请求的会话保持。
|
||
|
||
---
|
||
|
||
## Http_Client 类
|
||
|
||
### `__init__()`
|
||
初始化一个 `Http_Client` 实例。
|
||
|
||
#### 行为
|
||
- 创建一个持久化的 `requests.Session()` 实例
|
||
- 关闭 SSL 证书验证(`verify=False`)
|
||
- 注册响应钩子 `response_handler`
|
||
|
||
> 🔒 安全提示:关闭 SSL 验证可能导致中间人攻击,仅建议在测试环境使用。
|
||
|
||
---
|
||
|
||
### `prepped_handler(prepped)`
|
||
预请求处理器,可用于修改准备好的请求对象(如添加签名、日志等)。
|
||
|
||
#### 参数
|
||
- `prepped` (`PreparedRequest`):已准备好的请求对象
|
||
|
||
#### 默认行为
|
||
无操作(`pass`),可由子类重写以扩展功能。
|
||
|
||
---
|
||
|
||
### `response_handler(resp, *args, **kw)`
|
||
响应处理器钩子函数,在每次收到响应后触发。
|
||
|
||
#### 参数
|
||
- `resp` (`Response`):响应对象
|
||
- `*args`, `**kw`:额外参数(保留扩展性)
|
||
|
||
#### 返回值
|
||
- 返回原始 `resp`,不影响后续处理
|
||
|
||
> ✅ 可用于记录日志、性能监控等。
|
||
|
||
---
|
||
|
||
### `url2domain(url)`
|
||
从完整 URL 提取协议 + 主机部分(即域名层级)
|
||
|
||
#### 参数
|
||
- `url` (`str`):完整的 URL 地址
|
||
|
||
#### 返回值
|
||
- `str`:形如 `https://example.com` 的字符串
|
||
|
||
#### 示例
|
||
```python
|
||
client.url2domain("https://api.example.com/v1/users?id=1")
|
||
# 结果: "https://api.example.com"
|
||
```
|
||
|
||
#### 实现逻辑
|
||
取前三个 `/` 分隔的部分(协议、空、主机)
|
||
|
||
---
|
||
|
||
### `_webcall(...)`
|
||
核心 HTTP 请求执行方法,负责发送请求并处理基础响应。
|
||
|
||
#### 参数
|
||
| 参数 | 类型 | 默认值 | 说明 |
|
||
|----------|---------|-------|------|
|
||
| `url` | str | 必填 | 请求地址 |
|
||
| `method` | str | `"GET"` | HTTP 方法(GET/POST/PUT/DELETE/OPTION) |
|
||
| `params` | dict | `{}` | GET 请求为查询参数;非 GET 为表单数据 |
|
||
| `files` | dict | `{}` | 文件上传字段 |
|
||
| `headers` | dict | `{}` | 自定义请求头 |
|
||
| `stream` | bool | `False` | 是否启用流式响应 |
|
||
|
||
#### 内部流程
|
||
1. 解析域名 → 获取对应 session ID
|
||
2. 若存在 session,则在 headers 中加入 `'session': sessionid`
|
||
3. 构造 `Request` 对象并准备为 `PreparedRequest`
|
||
4. 调用 `prepped_handler()` 进行预处理
|
||
5. 发送请求
|
||
6. 处理响应:
|
||
- 状态码 `200`:检查是否有 `Set-Cookie`,更新 `hostsessions`
|
||
- `401`:抛出 `NeedLogin`
|
||
- `403`:抛出 `InsufficientPrivilege`
|
||
- 其他非 `200`:打印错误信息并抛出 `HTTPError`
|
||
|
||
#### 返回值
|
||
- 成功时返回 `requests.Response` 对象
|
||
|
||
---
|
||
|
||
### `webcall(...)`
|
||
对 `_webcall` 的增强包装,主要用于处理响应体内容。
|
||
|
||
#### 参数
|
||
同 `_webcall`
|
||
|
||
#### 功能
|
||
- 调用 `_webcall` 执行请求
|
||
- 若 `stream=True`,直接返回响应对象
|
||
- 否则尝试将响应解析为 JSON:
|
||
- 若解析成功且结果为字典:
|
||
- 检查是否存在 `'status'` 字段
|
||
- 若 `status == 'OK'`,返回 `'data'` 字段内容
|
||
- 否则返回整个 JSON 数据
|
||
- 若不是字典或无 `status`,原样返回
|
||
- 若 JSON 解析失败,返回文本内容(`resp.text`)
|
||
|
||
#### 返回值
|
||
- 解析后的数据(dict / list / str)或原始响应文本
|
||
|
||
---
|
||
|
||
### `__call__(...)`
|
||
使实例可被直接调用,代理到 `webcall` 方法。
|
||
|
||
#### 示例
|
||
```python
|
||
client = Http_Client()
|
||
result = client("https://api.example.com/data", method="GET")
|
||
```
|
||
|
||
---
|
||
|
||
## HTTP 方法封装
|
||
|
||
提供常用 HTTP 方法的快捷调用方式。
|
||
|
||
| 方法 | 等效于 |
|
||
|------|--------|
|
||
| `.get(...)` | `client(url, method='GET', ...)` |
|
||
| `.post(...)` | `client(url, method='POST', ...)` |
|
||
| `.put(...)` | `client(url, method='PUT', ...)` |
|
||
| `.delete(...)` | `client(url, method='DELETE', ...)` |
|
||
| `.option(...)` | `client(url, method='OPTION', ...)` |
|
||
|
||
所有方法均支持以下参数:
|
||
- `url`: 请求地址
|
||
- `params`: 参数(GET 查询参数 或 POST 表单数据)
|
||
- `headers`: 自定义头部
|
||
- `files`: 文件上传(仅 POST/PUT 有效)
|
||
- `stream`: 是否流式接收
|
||
|
||
---
|
||
|
||
## 使用示例
|
||
|
||
### 基本 GET 请求
|
||
```python
|
||
client = Http_Client()
|
||
data = client.get("https://api.example.com/users")
|
||
print(data)
|
||
```
|
||
|
||
### POST 提交表单
|
||
```python
|
||
payload = {"username": "admin", "password": "123456"}
|
||
resp = client.post("https://api.example.com/login", params=payload)
|
||
```
|
||
|
||
### 上传文件
|
||
```python
|
||
files = {'file': open('report.pdf', 'rb')}
|
||
resp = client.post("https://api.example.com/upload", files=files)
|
||
```
|
||
|
||
### 流式下载大文件
|
||
```python
|
||
resp = client.get("https://example.com/large-file.zip", stream=True)
|
||
with open("download.zip", "wb") as f:
|
||
for chunk in resp.iter_content(1024):
|
||
f.write(chunk)
|
||
```
|
||
|
||
### 异常捕获
|
||
```python
|
||
try:
|
||
data = client.get("https://api.example.com/secure-data")
|
||
except NeedLogin:
|
||
print("请先登录")
|
||
except InsufficientPrivilege:
|
||
print("权限不足")
|
||
except HTTPError as e:
|
||
print(f"HTTP 错误: {e}")
|
||
```
|
||
|
||
---
|
||
|
||
## 注意事项与改进建议
|
||
|
||
1. **SSL 验证关闭**
|
||
`self.s.verify = False` 存在安全风险,建议增加配置项控制是否关闭验证。
|
||
|
||
2. **`__expr__` 应为 `__repr__`**
|
||
当前 `HTTPError.__expr__` 方法不会被 Python 调用,请更正为 `__repr__`。
|
||
|
||
3. **Session Key 名称硬编码**
|
||
当前假设 Cookie 中第一个字段是 session ID,实际中可能需根据具体服务调整(如 `JSESSIONID`, `token` 等)。
|
||
|
||
4. **并发安全性**
|
||
`hostsessions` 是全局共享字典,在多线程环境下可能存在竞争条件,建议加锁或使用线程局部存储。
|
||
|
||
5. **缺少超时设置**
|
||
推荐在 `send()` 调用中添加 `timeout` 参数防止无限等待。
|
||
|
||
6. **headers 更新影响原始输入**
|
||
`headers.update(...)` 修改了传入的字典,建议复制一份再操作。
|
||
|
||
---
|
||
|
||
## 版本信息
|
||
|
||
- 编写语言:Python 3.x
|
||
- 第三方依赖:`requests >= 2.20.0`
|
||
- 许可:MIT(示例代码,实际项目需明确授权)
|
||
|
||
---
|
||
|
||
✅ 本库适合快速集成 RESTful API 调用,具备良好的扩展性和清晰的异常体系。 |