平台概览
冰梭开放平台以 REST API 形式开放平台的文件传输、协作与文件管理能力。服务端、浏览器、脚本或移动端——任何能发起 HTTP 请求的环境,都可以通过统一的签名鉴权调用这些端点,把冰梭的能力嵌入你自己的产品。
能力域
| 能力域 | 基础路径 | 端点 | 能力说明 |
|---|---|---|---|
| 传输 | /api/open/transfer 等 | 10 | P2P 直传、安全中转、任务查询与整文件下载 |
| 空间 | /api/open/workspace | 7 | 空间上下文、角色与成员管理 |
| 项目 | /api/open/projects | 12 | 项目生命周期、项目成员与项目文件(文件上传走直传会话) |
| 文件库 | /api/open/drive 等 | 15 | 个人文件库目录树、文件管理与分块直传上传 |
| 交付 | /api/open/delivery | 7 | 交付链接创建、配置、回执与下载 |
| 计费 | /api/open/billing | 3 | 积分与流量余额、消耗流水、套餐配额 |
| 审核 | /api/open/review | 2 | AI 质检报告、审片标注汇总(交付背书能力开放) |
调用方式
快速开始
从创建应用到收到第一个响应,通常只需几分钟。建议先通读本节建立整体认识,再按场景深入 签名鉴权、SDK 与左侧「API 参考」。
第一步:创建应用
- 注册并登录冰梭账号,进入 应用管理
- 创建应用,获取
AppKey与AppSecret——Secret 仅在创建时展示一次,请妥善保管,泄露可随时重置 - 按需配置 IP 白名单(最多 5 条);未配置则不校验来源
第二步:选择调用方式
- 浏览器 / Web 应用:使用官方 JavaScript SDK,签名、WebRTC 信令、分块上传等细节全部内置,见 SDK 安装与初始化
- 服务端 / 脚本:按 签名鉴权 自行计算签名并携带五个认证头调用,支持 SM3(默认)与 SHA-256 两种算法
第三步:发出第一个请求
以「传输策略查询」为例——GET 请求、无请求体,返回当前权益下可用的传输模式与限额:
$appKey = "your-app-key" $appSecret = "your-app-secret" $timestamp = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds() $nonce = [Guid]::NewGuid().ToString("N") $method = "GET" $path = "/api/open/transfer/strategy" # GET 请求无请求体,bodyHash 为空字符串,直接裸拼接后做 HMAC-SHA256 $stringToSign = $appKey + $timestamp + $nonce + $method + $path $hmac = New-Object System.Security.Cryptography.HMACSHA256 $hmac.Key = [Text.Encoding]::UTF8.GetBytes($appSecret) $signature = -join ($hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($stringToSign)) | ForEach-Object { $_.ToString("x2") }) Invoke-RestMethod -Uri "https://www.wringcloud.com$path" -Headers @{ "X-App-Key" = $appKey "X-Timestamp" = $timestamp "X-Nonce" = $nonce "X-Algorithm" = "SHA-256" "X-Signature" = $signature }
下一步
SDK 安装与初始化
冰梭开放平台提供 iceshuttle-js JavaScript SDK,适用于浏览器环境,内部封装了签名认证、WebRTC 信令、分块上传/下载等全部复杂逻辑。
浏览器端 SDK,支持 P2P 直传、安全中转和分块直传三种传输模式
引入方式
// 方式一:本地引入(下载 SDK 文件后放置到项目中) import { IceShuttle, downloadBlob } from './sdk/iceshuttle.esm.js'; // 方式二:官网下载引入(适合无构建工具的项目) // 下载地址:https://www.wringcloud.com/sdk/iceshuttle-js/dist/iceshuttle.min.js <script src="./sdk/iceshuttle.min.js"></script> <script> const { IceShuttle, downloadBlob } = window.IceShuttle; </script>
iceshuttle.min.js— 压缩版,体积最小,适合生产环境(script 标签引入)iceshuttle.esm.js— ES Module 格式,可读性好,适合开发调试(import 引入)iceshuttle.umd.js— UMD 格式,兼容 script 标签和 import 两种引入方式
初始化客户端
使用 AppKey 和 AppSecret 初始化 SDK 客户端,SDK 会自动处理签名认证。
import { IceShuttle } from 'iceshuttle-js'; const client = new IceShuttle({ appKey: 'your-app-key', // 必填:应用 Key appSecret: 'your-app-secret', // 必填:应用 Secret serverDomain: 'https://www.wringcloud.com', // 可选:服务器地址 debug: false // 可选:是否开启调试日志 });
初始化参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
appKey | string | 必填 | 应用 Key,在开放平台应用管理中获取 |
appSecret | string | 必填 | 应用 Secret,在开放平台应用管理中获取 |
serverDomain | string | 可选 | 服务器地址,默认 https://www.wringcloud.com |
debug | boolean | 可选 | 是否开启调试日志,默认 false |
大文件分块直传(v2.1.0+)
除 P2P 与安全中转外,SDK 还封装了开放平台的分块直传能力:文件字节由客户端凭预签名 URL 直连对象存储,不经过冰梭应用服务器,支持断点续传与并发上传。高层入口 uploadFile 一行完成全部五步(算哈希 → 初始化会话 → 并发上传 → 逐块回执 → 合并落地):
// 高层 API:自动断点续传 + 并发上传(默认 3 并发,可调 1-8) const result = await client.uploadFile(file, { bizType: 'drive', // drive=文件库 / project=项目 / collect=收集链接 bizRef: { folderId: 0 }, // 按 bizType 传入:目录 ID / 项目 ID / 收集 token onProgress: (p) => console.log(p + '%') }); // result:drive 返回 { transferId };project 返回 { transferId, fileId, projectId }; // collect 返回 { fileName, fileSize, autoAccepted } // 需要自行控制 complete 时机(或中途取消)时,使用低层 API //(createUploader 需完整会话参数,fileHash 可用 SDK 导出的 sha256Hex(file) 计算) const uploader = await client.createUploader({ bizType: 'drive', bizRef: { folderId: 0 }, fileName: file.name, fileSize: file.size, fileHash: await sha256Hex(file), concurrency: 4 }); try { await uploader.upload(file); // 仅完成分块直传与回执 const landed = await client.completeUploadSession(uploader.sessionKey); } catch (e) { await uploader.abort(); // 清理会话与已传分块 }
- 同一用户对相同内容(fileHash)重复上传时自动命中未完成会话,已确认分块直接跳过
- 文件库上传不计费;安全中转与交付下载按权益扣流量,配额校验在
complete落地时发生 - 协议细节见 文件库域 的分块直传会话说明与时序图
签名鉴权
所有开放 API 均需携带五个认证头。服务端验证签名、时间窗与 Nonce 唯一性后,以「App 创建者本人」身份执行请求——与页面登录同权。
认证头
| 请求头 | 必填 | 说明 |
|---|---|---|
X-App-Key | 必填 | 应用的 AppKey,在应用管理页获取 |
X-Timestamp | 必填 | Unix 秒级时间戳,与服务器时差超过 ±300 秒即拒绝 |
X-Nonce | 必填 | 随机串(建议 UUID),服务端校验唯一性,防止重放 |
X-Algorithm | 可选 | 摘要算法:SM3(默认,国密)或 SHA-256,用于请求体哈希与 HMAC 摘要 |
X-Signature | 必填 | HMAC 签名,十六进制小写(算法与 X-Algorithm 对应) |
签名算法
- 请求体哈希:
bodyHash = SM3(body)或SHA-256(body)(与 X-Algorithm 一致,默认 SM3),输出十六进制小写;GET 请求或空请求体时为空字符串。 - 构造签名串:按
appKey + timestamp + nonce + METHOD + path + bodyHash裸拼接(无分隔符、无换行)。METHOD 大写(GET/POST/PUT/DELETE);path 为请求路径(如/api/open/workspace/members/invite,不含域名与 query 参数)。 - 计算签名:
X-Signature = HMAC(appSecret, 签名串)。X-Algorithm 为SHA-256时用 HMAC-SHA256;SM3(默认)时用 HMAC-SM3。 - 发起请求:携带上述五个认证头调用任意开放 API。
// 裸拼接,无分隔符;bodyHash 与 HMAC 使用 X-Algorithm 声明的同一算法
- 时间戳窗口 ±300 秒,请校准服务器时钟
- Nonce 在有效窗口内必须唯一,重复即判重放(401)
- AppSecret 仅在创建应用时展示一次,可重置(原 Secret 立即失效),切勿写入前端代码
- 应用可配置最多 5 个 IP / 域名白名单,来源不符直接拦截(403)
统一响应格式
所有接口统一返回 {"code":num,"data":...,"message":"..."}:业务数据在 data,错误说明在 message,code 同时反映在 HTTP 状态码中。
PowerShell 调用示例(SHA-256)
# 0. 准备参数(时间戳为秒级) $appKey = "your-app-key" $appSecret = "your-app-secret" $timestamp = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds() $nonce = [Guid]::NewGuid().ToString("N") $method = "POST" $path = "/api/open/workspace/members/invite" $body = '{"contact":"dev@example.com","roleId":2,"expireDays":7}' # 1. 请求体哈希(X-Algorithm=SHA-256;SM3 需国密库) $sha = [System.Security.Cryptography.SHA256]::Create() $bodyHash = -join ($sha.ComputeHash([Text.Encoding]::UTF8.GetBytes($body)) | ForEach-Object { $_.ToString("x2") }) # 2. 签名串裸拼接 + HMAC-SHA256 $stringToSign = $appKey + $timestamp + $nonce + $method + $path + $bodyHash $hmac = New-Object System.Security.Cryptography.HMACSHA256 $hmac.Key = [Text.Encoding]::UTF8.GetBytes($appSecret) $signature = -join ($hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($stringToSign)) | ForEach-Object { $_.ToString("x2") }) # 3. 携带五个认证头发起请求 Invoke-RestMethod -Method Post -Uri "https://www.wringcloud.com$path" -Body $body -ContentType "application/json" -Headers @{ "X-App-Key" = $appKey "X-Timestamp" = $timestamp "X-Nonce" = $nonce "X-Algorithm" = "SHA-256" "X-Signature" = $signature }
P2P 直传
传输流程
发送文件
// 1. 创建 P2P 发送任务 const sender = await client.createP2PSender({ fileName: file.name, // 必填:文件名 fileSize: file.size, // 必填:文件大小(字节) password: '可选密码', // 可选:传输密码 maxReceiveCount: 1 // 可选:最大接收次数 }); // 2. 获取接收链接,分享给接收方 const receiveLink = sender.getReceiveLink(); console.log('接收链接:', receiveLink); // 3. 发送文件(SDK 自动并传输) await sender.sendFile(file, { onProgress: (percent) => { console.log(`传输进度: ${percent.toFixed(1)}%`); }, onComplete: (info) => { console.log('传输完成', info); }, onError: (err) => { console.error('传输失败:', err); }, onProcessing: (info) => { console.log(info.message); // 如 "正在校验文件..." } }); // 4. 取消传输(可选) await sender.cancel();
createP2PSender 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
fileName | string | 必填 | 文件名 |
fileSize | number | 必填 | 文件大小(字节) |
password | string | 可选 | 传输密码 |
maxReceiveCount | number | 可选 | 最大接收次数 |
sendFile 回调
| 回调 | 参数 | 说明 |
|---|---|---|
onProgress | percent: number | 传输进度百分比(0-100) |
onComplete | info: {fileName, fileSize} | 传输完成 |
onError | err: string | 传输错误 |
onProcessing | info: {message} | 处理中状态(如校验文件) |
P2PSender 方法
| 方法 | 返回值 | 说明 |
|---|---|---|
getReceiveLink() | string | 获取接收链接,分享给接收方 |
sendFile(file, callbacks) | Promise | 发送文件,自动 |
cancel() | Promise | 取消传输 |
接收文件
接收方通过链接中的 transferId 和 token 接收文件。
// 从接收链接中解析 transferId 和 token const receiver = await client.createP2PReceiver(transferId, token); // 获取文件信息 console.log('文件名:', receiver.getFileName()); // 接收文件 await receiver.receiveFile({ onProgress: (percent) => { console.log(`接收进度: ${percent.toFixed(1)}%`); }, onComplete: ({ blob, fileName, fileSize }) => { // 触发浏览器下载 downloadBlob(blob, fileName); }, onError: (err) => { console.error('接收失败:', err); } });
createP2PReceiver 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
transferId | string | 必填 | 传输 ID,从接收链接中获取 |
token | string | 必填 | 接收令牌,从接收链接中获取 |
P2PReceiver 方法
| 方法 | 返回值 | 说明 |
|---|---|---|
getFileName() | string | 获取文件名 |
receiveFile(callbacks) | Promise | 接收文件,onComplete 参数为 {blob, fileName, fileSize} |
安全中转
传输流程
发送文件
// 1. 创建安全中转任务 const sender = await client.createRelaySender({ fileName: file.name, // 必填:文件名 fileSize: file.size, // 必填:文件大小(字节) password: '可选密码', // 可选:传输密码 maxReceiveCount: 5, // 可选:最大下载次数 expireHours: 168 // 可选:链接有效期(小时) }); // 2. 获取下载链接,分享给接收方 const downloadLink = sender.getDownloadLink(); console.log('下载链接:', downloadLink); // 3. 上传文件(SDK 自动处理分块上传) await sender.sendFile(file, { onProgress: (percent) => { console.log(`上传进度: ${percent.toFixed(1)}%`); }, onComplete: (info) => { console.log('上传完成,等待接收方下载'); }, onError: (err) => { console.error('上传失败:', err); } }); // 4. 取消传输(可选) await sender.cancel();
createRelaySender 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
fileName | string | 必填 | 文件名 |
fileSize | number | 必填 | 文件大小(字节) |
password | string | 可选 | 传输密码 |
maxReceiveCount | number | 可选 | 最大下载次数 |
expireHours | number | 可选 | 链接有效期(小时) |
RelaySender 方法
| 方法 | 返回值 | 说明 |
|---|---|---|
getDownloadLink() | string | 获取下载链接,分享给接收方 |
sendFile(file, callbacks) | Promise | 上传文件,SDK 自动处理分块 |
cancel() | Promise | 取消传输 |
接收文件
接收方通过链接中的 transferId 和 token 下载文件。
// 从下载链接中解析 transferId 和 token const receiver = await client.createRelayReceiver(transferId, token); // 获取文件信息 console.log('文件名:', receiver.getFileName()); // 下载文件为 Blob const blob = await receiver.receiveFileAsBlob({ onProgress: (percent) => { console.log(`下载进度: ${percent.toFixed(1)}%`); } }); // 触发浏览器下载 downloadBlob(blob, receiver.getFileName());
createRelayReceiver 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
transferId | string | 必填 | 传输 ID,从下载链接中获取 |
token | string | 必填 | 下载令牌,从下载链接中获取 |
RelayReceiver 方法
| 方法 | 返回值 | 说明 |
|---|---|---|
getFileName() | string | 获取文件名 |
receiveFileAsBlob(callbacks) | Promise<Blob> | 下载文件为 Blob |
查询、取消与下载
查询任务状态
// 查询 P2P 传输状态 const p2pStatus = await client.getP2PTransferStatus(transferId); // 查询安全中转传输状态 const relayStatus = await client.getRelayTransferStatus(transferId);
取消传输
// 取消 P2P 传输 await client.cancelP2PTransfer(transferId); // 取消安全中转传输 await client.cancelRelayTransfer(transferId); // 或直接调用 sender.cancel() await sender.cancel();
下载工具
SDK 提供 downloadBlob 工具函数,用于触发浏览器文件下载。
import { downloadBlob } from 'iceshuttle-js'; // 触发浏览器下载 downloadBlob(blob, '文件名.txt');
错误码
所有接口统一返回 {"code":num,"data":...,"message":"..."}:业务数据在 data,错误说明在 message。
| 错误码 | 场景 | 说明 |
|---|---|---|
| 200 | 成功 | 业务数据在 data 中 |
| 400 | 参数错误 | 参数校验失败;或任务状态不允许(已取消 / 已完成 / 链接过期 / 不支持整文件下载) |
| 401 | 认证失败 | 缺少认证参数 / 无效的 AppKey / 签名验证失败 / 时间戳过期(±300 秒)/ Nonce 重放 |
| 403 | 禁止访问 | 应用被禁用或拉黑(拉黑时 message 携带原因)/ 无权限(非管理员、越权访问、直传会话跨应用操作)/ IP 白名单拦截 / 无效 token |
| 404 | 资源不存在 | 请求的资源不存在或已删除 |
| 410 | 资源已失效 | 保留期已过或接收 / 下载次数达上限 |
| 413 | 文件超限 | 单文件大小超出套餐限额,或超出套餐剩余积分额度 |
| 429 | 限流 | 请求过于频繁(默认每应用 100 次/分钟;分块直传凭证与回执端点放宽至 600 次/分钟),请稍后重试 |
| 500 | 服务器错误 | 服务端异常,请稍后重试 |
常见问题
P2P、安全中转和分块直传如何选择?
- P2P 直传:发送方和接收方同时在线,文件 2G 以内,追求速度和免费
- 安全中转:接收方可能离线,需要多次下载,文件较大,有套餐积分池权益
- 分块直传:把文件传进文件库 / 项目 / 收集链接(落库管理),任意大小,断点续传
AppSecret 丢失怎么办?
在 应用管理 页面,点击「重置Secret」获取新的 AppSecret。原 Secret 立即失效。
SDK 是否支持自动降级?
SDK 不支持自动降级。P2P 直传、安全中转和分块直传是三种独立的传输模式,需分别调用 createP2PSender、createRelaySender 或 uploadFile / createUploader。开发者可根据业务场景自行实现降级逻辑。
调用频率限制?
默认每个应用 100次/分钟。如需更高配额,请联系平台。
如何从接收链接中获取 transferId 和 token?
// P2P 接收链接格式:https://www.wringcloud.com/p2p/{transferId}?token={token} // 安全中转下载链接格式:https://www.wringcloud.com/r/{transferId}?token={token} function parseLink(link) { const url = new URL(link); const transferId = url.pathname.split('/').pop(); const token = url.searchParams.get('token'); return { transferId, token }; }
在线 Demo
我们提供了完整的 Demo 页面,包含 P2P 直传、安全中转、分块直传、文件接收的全部交互逻辑,开发者可基于此 Demo 定制自己的界面。
- 下载
demo/index.html和dist/iceshuttle.esm.js - 保持相对路径关系(demo 目录与 dist 目录同级)
- 用浏览器直接打开 index.html 即可运行
完整示例代码
import { IceShuttle, downloadBlob } from 'iceshuttle-js'; // 初始化 const client = new IceShuttle({ appKey: 'your-app-key', appSecret: 'your-app-secret' }); // ===== P2P 直传 ===== async function p2pSend(file) { const sender = await client.createP2PSender({ fileName: file.name, fileSize: file.size }); console.log('接收链接:', sender.getReceiveLink()); await sender.sendFile(file, { onProgress: (p) => console.log(p + '%'), onComplete: () => console.log('完成') }); } async function p2pReceive(transferId, token) { const receiver = await client.createP2PReceiver(transferId, token); await receiver.receiveFile({ onProgress: (p) => console.log(p + '%'), onComplete: ({ blob, fileName }) => downloadBlob(blob, fileName) }); } // ===== 安全中转 ===== async function relaySend(file) { const sender = await client.createRelaySender({ fileName: file.name, fileSize: file.size }); console.log('下载链接:', sender.getDownloadLink()); await sender.sendFile(file, { onProgress: (p) => console.log(p + '%'), onComplete: () => console.log('上传完成') }); } async function relayReceive(transferId, token) { const receiver = await client.createRelayReceiver(transferId, token); const blob = await receiver.receiveFileAsBlob({ onProgress: (p) => console.log(p + '%') }); downloadBlob(blob, receiver.getFileName()); } // ===== 分块直传(上传到文件库,v2.1.0+)===== async function directUpload(file) { const landed = await client.uploadFile(file, { bizType: 'drive', // drive / project / collect bizRef: { folderId: 0 }, onProgress: (p) => console.log(p + '%') }); console.log('落地结果:', landed); // { transferId } }
传输域
基础路径 /api/open/transfer 等。P2P 直传 2G 内免费;安全中转消耗套餐积分配额,支持离线接收与多次下载。
项目域
基础路径 /api/open/projects。项目生命周期、成员与项目文件。标注 项目管理员 的端点需管理员权限,非管理员调用返回 403。项目文件上传不设独立端点,走文件直传会话(bizType=project),落地时校验项目成员上传权限。
文件库域
基础路径 /api/open/drive。个人文件库目录树与文件管理(与页面端文件保护库同链路)。上传不计费;下载照走权益扣流量。
POST /api/open/upload-sessions 初始化会话(bizType=drive / project / collect,相同 fileHash 自动断点续传)→ ② …/{sessionKey}/credentials 批量取分块凭证(单次≤64)→ ③ 对每个凭证按 HTTP PUT 直传分块字节 → ④ …/{sessionKey}/chunks/{index}/ack 逐块回执 → ⑤ …/{sessionKey}/complete 服务端合并并落地(配额校验与计费归因在此发生);中途放弃调 abort 清理。 会话与应用隔离:直传会话归属创建它的应用,其他应用或页面端创建的会话均不可跨应用操作(返回 403)。图 · 开放平台大文件分块直传时序:控制面走签名 API,文件数据面由客户端直连 OSS,应用服务器全程不经手字节
交付域
基础路径 /api/open/delivery。交付链接全生命周期:创建、配置、状态控制、回执与下载。带 {id} 的端点会校验链接所属空间的归属(与页面端空间管理员同可见度)。
计费域
基础路径 /api/open/billing。三池积分、消耗明细与套餐配额。与页面端同规则:API 调用免费,下载照走权益扣流量;付费方=调用方(应用创建者)。
审核域
基础路径 /api/open/review。把平台审核能力接入你自己的系统:AI 质检报告(总结论、检查项明细与证据截图)与审片标注汇总(全量批注、锚点与解决状态)。调用者须为文件所属项目成员(与页面端审片室同口径);证据截图为预签名 URL(600 秒内有效)。与交付页「过程报告」同数据源——页面端面向被交付方输出脱敏版,开放平台面向服务方输出完整版。
空间域
基础路径 /api/open/workspace。空间上下文与成员管理。标注 空间管理员 的端点需管理员权限,非管理员调用返回 403。成员变更必须由他人操作(不能给自己设置角色、不能移除自己)。