6.0 KiB
Bricks 流媒体传输模块技术文档
概述
bricks.UpStreaming 和 bricks.down_streaming 是用于实现浏览器端流式数据上传与下载的 JavaScript 工具类,基于现代 Web API(如 ReadableStream 和 fetch)构建。该模块适用于需要实时上传二进制数据(如音频、视频流)或处理响应流的场景。
主要功能包括:
- 上行流(UpStreaming):通过
POST请求将数据以application/octet-stream格式分块发送至指定 URL。 - 下行流解析器(down_streaming):异步生成器函数,用于消费
Response.body的流式内容,并将其转换为字符串输出。
依赖说明
本模块依赖以下现代浏览器特性:
ReadableStreamHeadersfetch()API(支持duplex: 'full')async/await与async generator函数TextDecoder(隐含在String.fromCharCode使用中)
⚠️ 注意:
duplex: 'full'是处理流式请求所必需的,目前仅在部分现代浏览器(如 Chrome 105+)中支持。
命名空间初始化
bricks = window.bricks || {};
确保 bricks 全局命名空间存在,避免覆盖已有定义。
类:bricks.UpStreaming
继承自 bricks.JsWidget,提供流式上传能力。
继承关系
class UpStreaming extends bricks.JsWidget
需确保
bricks.JsWidget已正确定义并可用。
构造函数
constructor(opts)
参数
| 参数 | 类型 | 描述 |
|---|---|---|
opts |
Object | 配置对象,必须包含 url 字段 |
示例配置:
{
url: "https://example.com/upload"
}
实现逻辑
调用父类构造函数 super(opts),初始化组件基础属性。
方法
async go()
启动流式上传请求。
返回值
{Promise<Response>}:返回一个 resolve 为Response对象的 Promise。
实现细节
- 创建一个可读流
this.body,使用当前实例作为其源(source)。 - 设置请求头:
Content-Type: application/octet-stream
- 使用
fetch发起 POST 请求:fetch(this.url, { method: 'POST', headers: this.headers, duplex: 'full', body: this.body }) - 返回响应
Response对象。
💡
duplex: 'full'表示客户端可以同时写入请求体并读取响应,常用于流式接口。
send(data)
向流中写入一段数据。
参数
| 参数 | 类型 | 描述 |
|---|---|---|
data |
ArrayBuffer / Uint8Array 等 | 要发送的二进制数据块 |
实现
调用内部控制器的 enqueue 方法将数据推入流队列:
this.stream_ctlr.enqueue(data);
必须在调用
start()后才能使用此方法。
finish()
关闭写入流,表示所有数据已发送完毕。
实现
this.stream_ctlr.close();
通知流结束,触发底层请求完成。
start(controller)
流控制器初始化钩子(由 ReadableStream 调用)。
参数
| 参数 | 类型 | 描述 |
|---|---|---|
controller |
ReadableStreamController | 浏览器提供的流控制对象 |
实现
保存控制器引用以便后续调用:
this.stream_ctlr = controller;
此方法是
ReadableStream构造时自动调用的标准接口。
函数:bricks.down_streaming
异步生成器函数,用于逐段读取响应流并解码为字符串。
bricks.down_streaming = async function*(response)
参数
| 参数 | 类型 | 描述 |
|---|---|---|
response |
Response | 来自 fetch 的响应对象 |
返回值
{AsyncGenerator<string>}:异步生成器,每次yield一个字符串片段。
实现逻辑
- 若
response为空,则直接返回。 - 获取响应体的读取器:
response.body.getReader() - 循环调用
reader.read()直到流结束(done === true)。 - 将每一块
Uint8Array数据转换为字符串:String.fromCharCode(...value.value)❌ 注意:这种方式对非 ASCII 字符(如中文)可能出错,推荐使用
TextDecoder。 - 输出日志并
yield结果。
示例用法
for await (const chunk of bricks.down_streaming(resp)) {
console.log('Received:', chunk);
}
使用示例
上行流发送数据
const uploader = new bricks.UpStreaming({
url: '/api/stream-upload'
});
// 启动上传
const respPromise = uploader.go();
// 发送若干数据块
uploader.send(new TextEncoder().encode("Hello"));
uploader.send(new TextEncoder().encode("World"));
// 完成上传
uploader.finish();
// 获取响应
const resp = await respPromise;
console.log('Upload complete:', resp.status);
下行流接收数据
const response = await fetch('/api/stream-download');
for await (const textChunk of bricks.down_streaming(response)) {
console.log('Chunk:', textChunk);
}
注意事项与优化建议
-
✅ 兼容性警告
duplex: 'full'并非所有浏览器都支持,请在使用前检测环境支持情况。 -
⚠️ 字符编码问题
当前行内使用String.fromCharCode解码字节数组,不支持 UTF-8 多字节字符。
建议改进为使用TextDecoder:const decoder = new TextDecoder('utf-8'); let result = decoder.decode(value.value); -
🔒 错误处理缺失
当前代码未捕获fetch或reader.read()中可能出现的异常,建议添加try-catch。 -
📦 内存管理
大量频繁调用send()可能导致内存堆积,建议结合背压机制(backpressure)进行流控。
总结
| 功能 | 类/函数 | 用途 |
|---|---|---|
| 流式上传 | bricks.UpStreaming |
实现双向流上传数据 |
| 流式下载解析 | bricks.down_streaming |
异步解析响应流为字符串 |
该模块适用于实时音视频通信、大文件分片上传、AI 流式推理等场景,具备良好的扩展潜力。
文档版本:v1.0
最后更新:2025-04-05