@greentourasia/tus
v1.0.1
Published
Greentourasia TUS upload library
Downloads
24
Readme
🛰️ @greentourasia/tus
高可靠断点续传上传库,基于 tus.io 1.0 协议封装。
📦 设计目标
- 解耦 HTTP 传输与 tus 协议\
- 支持断点续传、页面刷新自动恢复\
- 可与任意 httpClient 适配(axios、fetch、gta-http)\
- 提供 React Hook(useTusUpload)\
- 可运行于浏览器 / Node / SSR / Electron 等环境
📁 目录结构
@greentourasia/tus/
├─ package.json
├─ README.md
└─ src/
├
├─ core/
│ ├─ tusClient.js
│ └─ localResumeStore.js
├─ index.js🚀 安装
npm install @greentourasia/tus1️⃣ httpClient 适配规范(必须阅读)
tusClient 不依赖任何具体 HTTP 库,你必须按以下约定提供 httpClient:
const httpClient = {
post(url, data, config) => Promise<{ status, headers, data }>,
head(url, config) => Promise<{ status, headers, data }>,
patch(url, data, config) => Promise<{ status, headers, data }>
}✔️ axios 适配示例
import axios from "axios";
import { createAxiosHttpClient } from "@greentourasia/tus";
const httpClient = createAxiosHttpClient(axios);✔️ gta-http 适配示例(推荐内部使用)
import { request } from "@greentourasia/http";
const httpClient = {
post : (url, data, config) => request.post(url, data, config),
head : (url, config) => request.head(url, config),
patch: (url, data, config) => request.patch(url, data, config),
};2️⃣ 创建 tus 客户端
import { createTusClient } from "@greentourasia/tus";
import { request } from "@greentourasia/http";
const httpClient = {
post: (url, data, config) => request.post(url, data, config),
head: (url, config) => request.head(url, config),
patch: (url, data, config) => request.patch(url, data, config),
};
export const tusService = createTusClient(httpClient, {
endpoint: "/upload", //后台接口路径
chunkSize: 1 * 1024 * 1024, //分片大小
meta: {
rawResponse: true, // 必须:需要读取 Location / Upload-Offset
timeout: 60000, //这里放大一点
maxRetries: 5, //重试
retryDelay: 500, //充实等待
retryMethods: ["head", "options", "patch", "post"],
skipAuth: true, // 跳过鉴权
},
});
3️⃣ API 文档
createTusClient(httpClient, options)
配置项 说明
endpoint 默认上传地址
chunkSize 分片大小(建议 ≥1MB)
meta 透传给 httpClient 的配置
返回:
{
uploadFile(),
clearResume(),
createUpload(),
getOffset()
}uploadFile(params)
参数:
字段 类型 说明
file File / Blob 必填
metadata object tus 协议 metadata(自动 base64)
namespace string 用于生成 resumeKey
onProgress function 上传进度回调
shouldStop function 返回 true 则取消上传
store object 自定义断点存储层(默认 localStorage)
返回:
{
uploadUrl,
size,
uploaded,
resumeKey,
aborted: boolean
}4️⃣ 断点续传机制说明
✔️ resumeKey 格式
namespace:endpoint:fileName:fileSize:lastModified✔️ 自动续传流程
- 读取本地 resumeKey 对应的 uploadUrl\
- 向 uploadUrl 发 HEAD → 获取 offset\
- 从 offset 开始 PATCH 分片上传\
- 成功后自动删除 resumeKey
✔️ uploadUrl 404 的处理
服务器可能清理掉过期上传,此时:
- 前端自动删除 resumeKey\
- 抛出
TUS_NOT_FOUND错误\ - 下次上传会从头开始
5️⃣ React 使用(useTusUpload)
import { useTusUpload } from "@greentourasia/tus";
import { tusService } from "./tus.service";
const { upload, cancel, state } = useTusUpload(tusService);
upload(file, {
metadata: { filename: file.name }
});state 内容:
{
uploading,
percent,
uploaded,
total,
error,
result,
file,
aborted
}6️⃣ Node 使用
import axios from "axios";
import { createAxiosHttpClient, createTusClient } from "@greentourasia/tus";
const httpClient = createAxiosHttpClient(axios);
const tus = createTusClient(httpClient);
await tus.uploadFile({
file: fs.readFileSync("./big.zip"),
endpoint: "https://example.com/files"
});7️⃣ 最佳实践
✔️ 二次封装成业务方法(推荐)
export const uploadMaterial = async (file, extraData) => {
return tusService.uploadFile({
file,
namespace: "material",
metadata: {
filename: file.name,
filetype: file.type,
...extraData,
},
});
};✔️ 进度条 UI 建议
- 每 50~100ms 更新一次 UI\
- 对小文件自动跳过过快闪烁
8️⃣ FAQ
❓ offset 不一致怎么办?
自动处理:收到 409 状态后自动重新 HEAD → PATCH。
❓ 如何继续一个中断的上传?
只要 file 信息一致:name + size + lastModified 相同 → 自动从断点续传。
❓ 为什么 metadata 需要 base64?
tus 协议要求:Upload-Metadata: key base64(value)
❓ chunkSize 调多少合适?
chunkSize 场景
1MB 默认推荐 2--5MB 大文件更高效 256KB 移动端弱网
🚀 发布流程
npm run build
npm pack --dry-run
npm publish --registry=https://npm.pkg.github.com© Greentourasia Frontend Engineering Team 适用于公司内部所有 Web / Admin 前端项目。
