CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Cloudflare 实战入门/课时/Stream 与媒体
RawBlame
课时目录12 节

Cloudflare 实战入门

  1. 01边缘计算概览
  2. 02Wrangler 与本地开发
  3. 03Workers 核心
  4. 04Workers KV
  5. 05R2 对象存储
  6. 06D1 数据库
  7. 07Queues 消息队列
  8. 08Durable Objects
  9. 09Workers AI
  10. 10Stream 与媒体
  11. 11安全与防护
  12. 12运维与集成

Stream 与媒体

视频/Image 处理与分发。

30 分钟

Stream 与媒体

这一课你将能做到

  1. 使用 Cloudflare Stream 上传、转码、分发视频,并通过签名 URL 控制访问
  2. 使用 Cloudflare Images 做图片缩放、格式转换(WebP/AVIF)、懒加载
  3. 理解视频流媒体协议(HLS/DASH)和边缘缓存策略

为什么要学

你的 Next.js 站点要加视频教程。如果直接把 MP4 扔到服务器上,用户播放时会遇到:加载慢、卡顿、不同设备兼容性问题、流量费爆炸。如果上传到 YouTube/Bilibili,又有广告、品牌不统一、无法自定义播放器。

人话:Cloudflare Stream 就是「白标的 YouTube」。你上传视频,它自动转码成多种码率、生成 HLS/DASH 流、全球 CDN 分发、提供可定制的播放器。Images 则是「自动图片 CDN」:上传原图,它自动生成多种尺寸和格式,按设备返回最优版本。

先建立图像

视频处理流程:
[上传 MP4] ──> [Stream 转码集群]
                    │
        ┌───────────┼───────────┐
        ▼           ▼           ▼
    [1080p]     [720p]      [480p]
        │           │           │
        └───────────┴───────────┘
                    │
              [HLS/DASH 打包]
                    │
              [全球 CDN 分发]
                    │
        ┌───────────┼───────────┐
        ▼           ▼           ▼
    [北京用户]  [纽约用户]  [伦敦用户]
    (就近节点)  (就近节点)  (就近节点)

图片处理流程:
[原图] ──> [Images]
              │
    ┌─────────┼─────────┐
    ▼         ▼         ▼
 [WebP]   [AVIF]    [JPEG]
 [100px]  [500px]   [2000px]
    │         │         │
    └─────────┴─────────┘
              │
        [边缘缓存 + 按需生成]

跟着做

步骤 1:上传视频到 Stream

# 直接上传(小文件)
curl -X POST \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -F "file=@/path/to/video.mp4" \
  https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/stream

响应:

{
  "result": {
    "uid": "xxxxxxxxxxxxxxxx",
    "playback": {
      "hls": "https://customer-xxx.cloudflarestream.com/xxxxxxxx/manifest/video.m3u8",
      "dash": "https://customer-xxx.cloudflarestream.com/xxxxxxxx/manifest/video.mpd"
    },
    "status": { "state": "ready" }
  }
}

步骤 2:在 Worker 中生成签名 URL(防盗链)

export interface Env {
  STREAM_SIGNING_KEY: string;
  ACCOUNT_ID: string;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    const videoUid = url.searchParams.get('uid');
    if (!videoUid) return new Response('Missing uid', { status: 400 });
    
    const expires = Math.floor(Date.now() / 1000) + 3600; // 1 小时后过期
    
    const token = await signToken(videoUid, expires, env.STREAM_SIGNING_KEY);
    const signedUrl = `https://customer-${env.ACCOUNT_ID}.cloudflarestream.com/${videoUid}/manifest/video.m3u8?token=${token}`;
    
    return Response.json({ url: signedUrl, expires });
  },
} satisfies ExportedHandler<Env>;

async function signToken(uid: string, expires: number, key: string): Promise<string> {
  const encoder = new TextEncoder();
  const data = encoder.encode(`${uid}.${expires}`);
  const keyData = encoder.encode(key);
  
  const cryptoKey = await crypto.subtle.importKey(
    'raw', keyData, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']
  );
  
  const signature = await crypto.subtle.sign('HMAC', cryptoKey, data);
  return btoa(String.fromCharCode(...new Uint8Array(signature)));
}

步骤 3:前端嵌入播放器

<stream src="xxxxxxxxxxxxxxxx" controls></stream>
<script data-cfasync="false" defer src="https://embed.videodelivery.net/embed/r4xu.fla9.latest.js"></script>

步骤 4:使用 Images 做响应式图片

上传图片到 Images(Dashboard 或 API),然后在 HTML 中使用:

<img
  src="https://imagedelivery.net/{account_hash}/{image_id}/public"
  srcset="
    https://imagedelivery.net/{account_hash}/{image_id}/w=400 400w,
    https://imagedelivery.net/{account_hash}/{image_id}/w=800 800w,
    https://imagedelivery.net/{account_hash}/{image_id}/w=1200 1200w
  "
  sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px"
  alt="示例图片"
/>

Images 会自动根据设备 DPR 和屏幕宽度返回最合适的尺寸和格式。

步骤 5:Worker 动态生成图片变体

export default {
  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);
    const imageUrl = url.searchParams.get('url');
    const width = url.searchParams.get('w') ?? '800';
    
    // 通过 Cloudflare Image Resizing 动态缩放
    const resized = `https://your-domain.com/cdn-cgi/image/width=${width},format=auto/${imageUrl}`;
    
    return fetch(resized, {
      cf: { image: { width: parseInt(width), format: 'auto' } }
    });
  },
} satisfies ExportedHandler<Env>;

讲清楚要点

  1. Stream 自动转码:上传一个 MP4,Stream 自动生成 1080p/720p/480p/360p 多种码率,打包成 HLS 和 DASH。你不需要懂 FFmpeg。
  2. HLS 和 DASH:HLS 是 Apple 的协议,iOS/Safari 原生支持;DASH 是国际标准,Android/Chrome 支持更好。Stream 同时生成两者,播放器自动选择。
  3. 签名 URL 防盗链:默认视频 URL 是公开的。用签名 URL 可以控制「谁能在什么时间范围内播放」,适合付费内容。
  4. Images 按需生成:你不需要提前生成 10 种尺寸。Images 会根据 URL 参数(w=400)实时生成并缓存,边缘节点直接返回。
  5. 格式自动协商:format=auto 会根据浏览器支持自动返回 WebP 或 AVIF。Chrome 给 WebP,Safari 给 JPEG,无需人工干预。

你可能会懵的地方

  • Stream 和直接放 R2 有什么区别? R2 是原始文件存储,没有转码、没有自适应码率、没有播放器。Stream 是完整的视频 SaaS:转码、CDN、播放器、分析、DRM(付费)。自己用 R2 + FFmpeg + HLS.js 也能做,但工程量巨大。

  • Images 和 Image Resizing 有什么区别? Images 是存储 + 处理的一体化服务;Image Resizing 是只处理(源图可以在任何地方)。Images 适合「图片不多但要求体验好」的场景;Image Resizing 适合「已有图片源,只需要加速」的场景。

  • Stream 支持直播吗? 支持。Stream Live 可以接收 RTMP 推流,自动转码分发。适合活动直播、在线课程。

  • 视频审核怎么做? Stream 有内置的 NSFW 检测(付费)。也可以在上传后触发 Webhook,用 Workers AI 做自定义审核。

  • 免费额度够吗? Stream 按存储分钟数和观看分钟数计费,没有免费额度。Images 有免费额度(每月 10 万次请求)。个人项目用 Images 足够,Stream 建议先小范围测试。

错法对照

错法问题正解
直接把 MP4 放 R2 让用户下载没有自适应码率,大文件加载慢用 Stream 转码 + HLS 分发
不设置签名 URL视频被恶意盗链,流量费爆炸用签名 URL + 过期时间
图片只提供一种尺寸手机加载 4K 图,浪费带宽用 Images 的 srcset 响应式
用 <img src="original.jpg">原图 5MB,首屏加载 10 秒用 Images 的 w=800,format=auto
直播用普通 MP4 推流延迟高、无法互动用 Stream Live 的 RTMP/WebRTC

卡点急救

  1. 视频上传后一直 processing:大文件转码需要时间(几分钟到几十分钟)。检查 Dashboard 的转码进度;如果卡住,重新上传。
  2. 签名 URL 403:检查签名算法是否正确;检查 expires 是否过期;检查 uid 是否匹配。
  3. Images 返回原图而不是 WebP:确认 URL 中有 format=auto;确认浏览器支持 WebP(Chrome/Edge/Firefox 支持,Safari 14+ 支持)。

面试常问

  • HLS 和 DASH 的核心区别? HLS 是 Apple 的协议,基于 TS 分片,iOS/Safari 原生支持;DASH 是 MPEG 国际标准,基于 fMP4 分片,Android/Chrome 支持更好。现代播放器(Video.js、Shaka Player)通常两者都支持,自动降级。

  • 自适应码率(ABR)的原理? 播放器根据当前网络带宽、设备性能、缓冲区水位,动态选择最合适的码率。Stream 会自动生成多码率清单(M3U8/MPD),播放器内置 ABR 算法。

  • Cloudflare Images 和 Cloudinary 怎么比? Images 深度集成 Cloudflare CDN,边缘处理延迟低;Cloudinary 功能更全(AI 抠图、视频处理、数字资产管理)。如果已经在 Cloudflare 生态,Images 更自然;如果需要复杂图片编辑,Cloudinary 更强。

自测三问

  1. 为什么视频流媒体要用 HLS/DASH 而不是直接播放 MP4?
  2. 签名 URL 的签名算法是什么?怎么防止伪造?
  3. Images 的 format=auto 是怎么工作的?浏览器和服务器各做了什么?

小结一句话

Cloudflare Stream 和 Images 把视频转码、自适应码率、图片响应式、格式协商这些复杂工程变成了「上传即用」的 SaaS,配合 Worker 签名 URL 可以构建安全、高性能的媒体分发系统。

延伸

  • Stream 官方文档
  • Images 官方文档
  • 下一课:安全与防护,学习 WAF、TLS、Bot 管理与边缘安全模型。
加载本节练习…
← 上一课Workers AI下一课 →安全与防护