创作者直接上传(Direct creator uploads)让您的终端用户直接向 Cloudflare Stream 上传视频,而无需向客户端暴露 API token。您可以使用基本 POST 请求或 tus 协议实现创作者直接上传。使用以下图表决定使用哪种方法:
flowchart LR
accTitle: 创作者直接上传决策流程
accDescr: 根据文件大小和连接可靠性选择基本 POST 上传或 tus 协议的决策流程
A{视频是否超过 200 MB?}
A -->|是| B[必须使用 tus 协议]:::link
A -->|否| C{终端用户是否有稳定连接?}
C -->|是| D[建议使用基本 POST]:::link
C -->|否| E[tus 协议可选,但建议使用]:::link
classDef link text-decoration:underline,color:#F38020
click B "#direct-creator-uploads-with-tus-protocol" "了解 tus 协议"
click D "#basic-post-request" "查看基本 POST 说明"
click E "#direct-creator-uploads-with-tus-protocol" "了解 tus 协议"
如果终端用户的视频小于 200 MB 且连接稳定,建议使用此方法。如果终端用户的连接不稳定,建议使用 tus 协议。
要启用 POST 请求的创作者直接上传:
使用 Direct upload API 生成唯一的一次性上传 URL。
curl https://api.cloudflare.com/client/v4/accounts/{account_id}/stream/direct_upload \
--header 'Authorization: Bearer <API_TOKEN>' \
--data '{
"maxDurationSeconds": 3600
}'{
"result": {
"uploadURL": "https://upload.videodelivery.net/f65014bc6ff5419ea86e7972a047ba22",
"uid": "f65014bc6ff5419ea86e7972a047ba22"
},
"success": true,
"errors": [],
"messages": []
}请参阅完整的 Stream REST API 和 SDK 参考,了解如何从外部应用程序使用 REST API,以及适用于外部 TypeScript、Python 或 Go 应用的预生成 SDK。
export default {
async fetch(request, env, ctx): Promise<Response> {
const directUpload = await env.STREAM.createDirectUpload({
maxDurationSeconds: 3600,
});
return new Response(JSON.stringify(directUpload));
},
} satisfies ExportedHandler<{ STREAM: StreamBinding }>;{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "<ENTER_WORKER_NAME>",
"main": "src/index.ts",
"compatibility_date": "$today",
"observability": {
"enabled": true
},
"stream": {
"binding": "STREAM"
}
}请参阅完整的 Workers Stream 绑定 API 参考。
使用上一步中的 uploadURL,用户可以上传大小限制为 200 MB 的视频文件。请参阅以下示例请求。
curl --request POST \
--form file=@/Users/mickie/Downloads/example_video.mp4 \
https://upload.videodelivery.net/f65014bc6ff5419ea86e7972a047ba22成功上传返回 200 HTTP 状态码响应。如果上传不符合创建时定义的上传约束或大小超过 200 MB,响应将返回 4xx HTTP 状态码。
如果终端用户的视频超过 200 MB,必须使用 tus 协议。即使文件小于 200 MB,如果终端用户的连接可能不稳定,Cloudflare 也建议使用 tus 协议,因为它支持断点续传。有关 tus 协议要求、其他客户端示例和上传选项的详细信息,请参阅可恢复和大文件 (tus)。
以下图表展示了此过程两个步骤的交互方式:
sequenceDiagram accTitle: 使用 tus 的创作者直接上传时序图 accDescr: 展示后端配置 tus 上传 URL 和终端用户直接上传到 Stream 的两步流程 participant U as 终端用户 participant B as 您的后端 participant S as Cloudflare Stream U->>B: 发起上传请求 B->>S: 请求 tus 上传 URL(已认证) S->>B: 返回一次性上传 URL B->>U: 返回一次性上传 URL U->>S: 使用 tus 直接上传视频
以下示例展示如何构建 Worker,向终端用户返回一次性上传 URL。对于 tus 协议上传,后端必须传递 Tus-Resumable、Upload-Length 和 Upload-Metadata 头。一次性上传 URL 在响应的 Location 头中返回,而非响应体中。
export async function onRequest(context) {
const { request, env } = context;
const { CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_API_TOKEN } = env;
const endpoint = `https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/stream?direct_user=true`;
const response = await fetch(endpoint, {
method: "POST",
headers: {
Authorization: `bearer ${CLOUDFLARE_API_TOKEN}`,
"Tus-Resumable": "1.0.0",
"Upload-Length": request.headers.get("Upload-Length"),
"Upload-Metadata": request.headers.get("Upload-Metadata"),
},
});
const destination = response.headers.get("Location");
return new Response(null, {
headers: {
"Access-Control-Expose-Headers": "Location",
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Origin": "*",
Location: destination,
},
});
}在 tus 客户端中直接使用后端端点。请参阅以下完整示例,演示如何将步骤 1 的后端与 uppy tus 客户端配合使用。
<html>
<head>
<link
href="https://releases.transloadit.com/uppy/v3.0.1/uppy.min.css"
rel="stylesheet"
/>
</head>
<body>
<div id="drag-drop-area" style="height: 300px"></div>
<div class="for-ProgressBar"></div>
<button class="upload-button" style="font-size: 30px; margin: 20px">
Upload
</button>
<div class="uploaded-files" style="margin-top: 50px">
<ol></ol>
</div>
<script type="module">
import {
Uppy,
Tus,
DragDrop,
ProgressBar,
} from "https://releases.transloadit.com/uppy/v3.0.1/uppy.min.mjs";
const uppy = new Uppy({ debug: true, autoProceed: true });
const onUploadSuccess = (el) => (file, response) => {
const li = document.createElement("li");
const a = document.createElement("a");
a.href = response.uploadURL;
a.target = "_blank";
a.appendChild(document.createTextNode(file.name));
li.appendChild(a);
document.querySelector(el).appendChild(li);
};
uppy
.use(DragDrop, { target: "#drag-drop-area" })
.use(Tus, {
endpoint: "/api/get-upload-url",
chunkSize: 150 * 1024 * 1024,
})
.use(ProgressBar, {
target: ".for-ProgressBar",
hideAfterFinish: false,
})
.on("upload-success", onUploadSuccess(".uploaded-files ol"));
const uploadBtn = document.querySelector("button.upload-button");
uploadBtn.addEventListener("click", () => uppy.upload());
</script>
</body>
</html>有关使用 tus 和客户端代码示例的更多详情,请参阅可恢复和大文件 (tus)。
使用 tus 时,您可以应用与基本创作者直接上传相同的约束。为此,您必须在第一个请求(由上述 Worker 发出)的 Upload-Metadata 请求头中传递 expiry 和 maxDurationSeconds。执行实际文件上传的后续请求将忽略 Upload-Metadata 值。
Upload-Metadata 头应包含键值对。键为文本,值应编码为 base64。用空格(而非等号)分隔键和值。要连接多个键值对,使用逗号且不加额外空格。
在以下示例中,Upload-Metadata 头指示 Stream 仅接受最大视频时长 10 分钟、在过期时间戳之前上传的视频,并将此视频设为私有:
'Upload-Metadata: maxDurationSeconds NjAw,requiresignedurls,expiry MjAyNC0wMi0yN1QwNzoyMDo1MFo='
NjAw 是 "600"(或 10 分钟)的 base64 编码值。
MjAyNC0wMi0yN1QwNzoyMDo1MFo= 是 "2024-02-27T07:20:50Z"(RFC3339 格式时间戳)的 base64 编码值
创建唯一的一次性上传 URL 后,您应保留响应中返回的唯一标识符(uid)以跟踪用户的上传进度。
您可以通过以下方式跟踪上传进度:
-
使用获取视频详情 API 端点配合
uid。 -
创建 webhook 订阅以接收视频状态通知。这些通知包含
uid。