391 lines
10 KiB
Markdown
391 lines
10 KiB
Markdown
# Bricks HTTP 模块技术文档
|
||
|
||
本模块为 `bricks` 前端框架提供了一套完整的 HTTP 请求处理工具集,支持多种响应类型(文本、JSON、二进制流等),并封装了自动参数注入、错误处理、会话管理与登录重定向等功能。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
- [概述](#概述)
|
||
- [核心功能](#核心功能)
|
||
- [公共函数](#公共函数)
|
||
- [基类:`HttpText`](#基类httptext)
|
||
- [派生类](#派生类)
|
||
- [`HttpArrayBuffer`](#httparraybuffer)
|
||
- [`HttpBin`](#httpbin)
|
||
- [`HttpResponse`](#httpresponse)
|
||
- [`HttpResponseStream`](#httpresponsestream)
|
||
- [`HttpRaw`](#httpraw)
|
||
- [`HttpJson`](#httpjson)
|
||
- [快捷方法](#快捷方法)
|
||
- [使用示例](#使用示例)
|
||
|
||
---
|
||
|
||
## 概述
|
||
|
||
`bricks.Http*` 系列类基于 `fetch` API 构建,旨在统一前端网络请求行为。主要特性包括:
|
||
|
||
- 自动附加设备信息和会话参数
|
||
- 支持 GET/POST 请求及 FormData 或 JSON 数据格式
|
||
- 统一的错误提示机制(401、403、其他错误)
|
||
- 可扩展的响应处理器(文本、JSON、流式解析等)
|
||
- 登录拦截与跳转支持(待完善)
|
||
|
||
该模块适用于 Web 应用中需要与后端服务交互的所有场景。
|
||
|
||
---
|
||
|
||
## 核心功能
|
||
|
||
| 功能 | 描述 |
|
||
|------|------|
|
||
| 参数合并 | 自动注入 `_webbricks_`, 屏幕宽高, 移动端标识等参数 |
|
||
| 会话管理 | 从响应头读取 `Set-Cookie` 并保存会话;发送时自动携带 |
|
||
| 错误处理 | 对 401、403 和非 OK 状态码进行统一 UI 提示 |
|
||
| 登录重定向 | 当返回 401 且存在 `login_url` 时触发登录流程(目前未完全实现) |
|
||
| 流式响应处理 | 支持逐行处理 chunked 响应数据(如 Server-Sent Events) |
|
||
|
||
---
|
||
|
||
## 公共函数
|
||
|
||
### `url_params(data)`
|
||
|
||
将对象转换为 URL 查询字符串。
|
||
|
||
#### 参数
|
||
- `data`: `{[key: string]: any}` — 要编码的对象
|
||
|
||
#### 返回值
|
||
- `string` — 格式化后的查询字符串(例如 `"a=1&b=2"`)
|
||
|
||
#### 示例
|
||
```js
|
||
url_params({a: 1, b: 'hello'}) // → "a=1&b=hello"
|
||
```
|
||
|
||
> ⚠️ 所有值都会通过 `encodeURIComponent` 编码。
|
||
|
||
---
|
||
|
||
## 基类:`HttpText`
|
||
|
||
所有 HTTP 客户端类的基类。
|
||
|
||
### 构造函数 `constructor(headers?)`
|
||
|
||
#### 参数
|
||
- `headers?`: `{[key: string]: string}` — 自定义请求头,默认为 `{ Accept: "text/html" }`
|
||
|
||
#### 行为说明
|
||
- 若未传入 `headers`,默认使用:
|
||
```js
|
||
{ "Accept": "text/html" }
|
||
```
|
||
- 使用 `bricks.extend()` 合并默认头与用户头。
|
||
- 自动收集以下上下文参数作为请求参数:
|
||
- `_webbricks_`: 固定值 `1`
|
||
- `width`: 屏幕宽度(来自 `bricks.app.screenWidth()`)
|
||
- `height`: 屏幕高度(来自 `bricks.app.screenHeight()`)
|
||
- `_is_mobile`: 是否为移动端(`'1'` 或 `'0'`)
|
||
|
||
> ✅ 这些参数会在每次请求中自动附加。
|
||
|
||
### 方法
|
||
|
||
#### `url_parse(url)`
|
||
|
||
解析 URL 中的查询参数,并将其合并到内部 `this.params` 中。
|
||
|
||
##### 参数
|
||
- `url`: `string` — 原始 URL(含 query)
|
||
|
||
##### 返回值
|
||
- `string` — 清除 query 的基础 URL
|
||
|
||
##### 示例
|
||
```js
|
||
const client = new bricks.HttpText();
|
||
client.url_parse("/api/data?a=1&b=2");
|
||
// 结果:client.params 包含 a=1, b=2
|
||
// 返回 "/api/data"
|
||
```
|
||
|
||
#### `add_own_params(params)`
|
||
|
||
合并用户参数与内部参数(包括 session)。
|
||
|
||
##### 参数
|
||
- `params`: `Object | FormData | null`
|
||
|
||
##### 返回值
|
||
- `Object | FormData` — 合并后的参数对象
|
||
|
||
##### 行为逻辑
|
||
- 如果是 `FormData`,直接追加键值对
|
||
- 否则创建新对象,合并 `this.params` 和 `params`
|
||
- 若存在 `bricks.app.get_session()`,额外添加 `session` 字段
|
||
|
||
#### `add_own_headers(headers)`
|
||
|
||
合并自定义请求头与实例默认头。
|
||
|
||
##### 参数
|
||
- `headers`: `{[key: string]: string} | null`
|
||
|
||
##### 返回值
|
||
- `Object` — 合并后的 headers
|
||
|
||
> 使用 `Object.assign(this.headers, headers)` 实现浅合并。
|
||
|
||
#### `async bricks_fetch(url, {method, headers, params})`
|
||
|
||
底层 `fetch` 封装,负责构建最终请求选项。
|
||
|
||
##### 参数
|
||
- `url`: `string` — 请求地址
|
||
- `method`: `'GET'|'POST'|'HEAD'|...` — HTTP 方法(默认 `'GET'`)
|
||
- `headers`: `Object` — 请求头
|
||
- `params`: `Object|FormData` — 请求参数
|
||
|
||
##### 处理逻辑
|
||
| 条件 | 行为 |
|
||
|------|------|
|
||
| `params instanceof FormData` | 强制设为 POST,`body = params` |
|
||
| `GET/HEAD` 请求 | 将 `params` 转为 query string 拼接到 URL |
|
||
| 其他方法(如 POST) | `body = JSON.stringify(params)` |
|
||
|
||
##### 返回值
|
||
- `Response` — fetch 返回的原生响应对象
|
||
|
||
#### `async httpcall(url, opts)`
|
||
|
||
高层封装,包含状态码判断与错误处理。
|
||
|
||
##### 参数
|
||
- `url`: `string`
|
||
- `opts`: `{method, headers, params}`
|
||
|
||
##### 流程
|
||
1. 调用 `bricks_fetch` 发起请求
|
||
2. 检查响应状态:
|
||
- **401** 且配置了 `bricks.app.login_url` → 触发 `withLoginInfo`
|
||
- **403** → 显示“禁止访问”弹窗
|
||
- 非 `ok` → 显示通用错误弹窗
|
||
3. 成功则调用 `get_result_data()` 获取结果
|
||
4. 解析 `Set-Cookie` 并调用 `bricks.app.save_session(session)` 保存会话
|
||
|
||
##### 返回值
|
||
- `string | null` — 成功返回响应内容,失败返回 `null`
|
||
|
||
#### `async withLoginInfo(url, params)`
|
||
|
||
处理 401 时尝试重新登录(当前仅为占位实现)。
|
||
|
||
> ❗ 当前仅创建一个 `urlwidget` 加载登录页,未完成回调或重试逻辑。
|
||
|
||
#### `async get_result_data(resp)`
|
||
|
||
提取响应体数据的方法(可被子类覆盖)。
|
||
|
||
##### 默认实现(`HttpText`)
|
||
```js
|
||
return await resp.text();
|
||
```
|
||
|
||
---
|
||
|
||
## 派生类
|
||
|
||
### `HttpArrayBuffer`
|
||
|
||
继承自 `HttpText`,用于下载二进制文件(如字体、模型等)。
|
||
|
||
#### 重写方法
|
||
```js
|
||
async get_result_data(resp) {
|
||
return await resp.arrayBuffer();
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### `HttpBin`
|
||
|
||
继承自 `HttpText`,以 Blob 形式获取响应(适合图片、音频等)。
|
||
|
||
#### 重写方法
|
||
```js
|
||
async get_result_data(resp) {
|
||
return await resp.blob();
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### `HttpResponse`
|
||
|
||
继承自 `HttpText`,直接返回原始 `Response` 对象。
|
||
|
||
#### 重写方法
|
||
```js
|
||
async get_result_data(resp) {
|
||
return resp;
|
||
}
|
||
```
|
||
|
||
> ✅ 适用于需手动处理 header 或 stream 的高级场景。
|
||
|
||
---
|
||
|
||
### `HttpResponseStream`
|
||
|
||
继承自 `HttpResponse`,专用于处理流式响应(如 SSE)。
|
||
|
||
#### 方法:`async handle_chunk(resp, handler)`
|
||
|
||
逐行解析 chunked 文本流,并调用 `handler(line)`。
|
||
|
||
##### 参数
|
||
- `resp`: `Response` — fetch 返回的响应对象
|
||
- `handler`: `(line: string) => void` — 每一行数据的处理器
|
||
|
||
##### 实现细节
|
||
- 使用 `ReadableStream.getReader()` + `TextDecoder`
|
||
- 按 `\n` 分割缓冲区,确保跨 chunk 边界正确切分
|
||
- 最终剩余内容也会传递给 `handler`
|
||
|
||
##### 示例用法
|
||
```js
|
||
const streamClient = new bricks.HttpResponseStream();
|
||
const resp = await streamClient.get('/stream-endpoint');
|
||
await streamClient.handle_chunk(resp, (line) => {
|
||
console.log('Received:', line);
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
### `HttpRaw`
|
||
|
||
与 `HttpBin` 相同,返回 `Blob`。
|
||
|
||
> ⚠️ 注释中可能表示未来用途不同,但当前实现与 `HttpBin` 完全一致。
|
||
|
||
---
|
||
|
||
### `HttpJson`
|
||
|
||
专用于 JSON 接口通信,设置默认 Accept 头并解析 JSON 响应。
|
||
|
||
#### 构造函数增强
|
||
```js
|
||
this.headers = { "Accept": "application/json" };
|
||
bricks.extend(this.headers, headers); // 用户头可覆盖
|
||
```
|
||
|
||
#### 重写方法
|
||
```js
|
||
async get_result_data(resp) {
|
||
return await resp.json();
|
||
}
|
||
```
|
||
|
||
> ✅ 推荐用于 RESTful API 调用。
|
||
|
||
---
|
||
|
||
## 快捷方法
|
||
|
||
模块末尾导出多个常用快捷函数,绑定到全局命名空间:
|
||
|
||
| 变量名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
| `bricks.hc` | `new HttpText()` | 文本客户端实例 |
|
||
| `bricks.tget` | `Function` | `hc.get` 的绑定方法(GET 文本) |
|
||
| `bricks.tpost` | `Function` | `hc.post` 的绑定方法(POST 文本) |
|
||
| `bricks.jc` | `new HttpJson()` | JSON 客户端实例 |
|
||
| `bricks.jcall` | `Function` | `jc.httpcall` 的绑定方法(调用 JSON 接口) |
|
||
| `bricks.jget` | `Function` | `jc.get` 的绑定方法(GET JSON) |
|
||
| `bricks.jpost` | `Function` | `jc.post` 的绑定方法(POST JSON) |
|
||
|
||
### 示例
|
||
```js
|
||
// 获取 HTML 内容
|
||
const html = await bricks.tget('/page', { params: { id: 123 } });
|
||
|
||
// 调用 JSON 接口
|
||
const data = await bricks.jpost('/api/user', {
|
||
headers: { 'X-Token': 'abc' },
|
||
params: { name: 'Alice' }
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 使用示例
|
||
|
||
### 1. 发送普通 GET 请求
|
||
```js
|
||
const client = new bricks.HttpText();
|
||
const result = await client.get('/api/hello', {
|
||
params: { q: 'test' }
|
||
});
|
||
console.log(result); // 输出服务器返回的文本
|
||
```
|
||
|
||
### 2. 发送 JSON POST 请求
|
||
```js
|
||
const jsonClient = new bricks.HttpJson();
|
||
const user = await jsonClient.post('/api/users', {
|
||
params: { name: 'Bob', age: 30 }
|
||
});
|
||
// 自动设置 Content-Type 和 Accept,并解析 JSON
|
||
```
|
||
|
||
### 3. 下载文件为 ArrayBuffer
|
||
```js
|
||
const bufferClient = new bricks.HttpArrayBuffer();
|
||
const resp = await bufferClient.get('/model.bin');
|
||
const arrayBuf = await resp; // 已是 arrayBuffer
|
||
```
|
||
|
||
### 4. 处理实时日志流
|
||
```js
|
||
const streamClient = new bricks.HttpResponseStream();
|
||
const resp = await streamClient.get('/logs/stream');
|
||
await streamClient.handle_chunk(resp, (line) => {
|
||
console.log('[LOG]', line);
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 注意事项
|
||
|
||
- 依赖 `bricks.app` 提供 `screenWidth()`, `screenHeight()`, `get_session()`, `save_session()` 等方法
|
||
- 依赖 `bricks.extend(obj, src)` 实现对象合并(类似 jQuery.extend)
|
||
- `objget(headers, 'Set-Cookie')` 用于安全获取响应头(需外部定义)
|
||
- 登录流程尚未完整实现,`withLoginInfo` 仅为原型
|
||
|
||
---
|
||
|
||
## 待优化建议
|
||
|
||
| 问题 | 建议改进 |
|
||
|------|---------|
|
||
| `bufffer` 拼写错误 | 修复 `if (buffer != ''){ yield bufffer; }` 中的拼写 |
|
||
| `withLoginInfo` 无实际登录能力 | 应支持模态框输入并回调重试请求 |
|
||
| `handle_chunk` 正则 `/\\r?\\n/gm` 不必要 | 可简化为 `.split('\n')` |
|
||
| `bricks_fetch` 中 `method = 'POST'` 修改外层变量风险 | 应使用局部变量 |
|
||
|
||
---
|
||
|
||
## 版本信息
|
||
|
||
- 创建时间:未知
|
||
- 框架版本:Bricks Framework v1.x+
|
||
- 作者:Bricks Team
|
||
|
||
> 文档最后更新:2025年4月5日 |