# Cloudflare R2:存储桶、CORS 与分发 创建 R2 存储桶,配置上传和播放 CORS,连接自定义域或 r2.dev 测试 URL,并通过 DRM-X 6.0 验证上传。 加密视频和 DRM 许可证通过不同路径传输 CDN 负责传输加密视频。您的后端检查观看权限,DRM 许可证服务则授权兼容设备解密播放。 - 01**存储 / CDN** 向播放器传输加密媒体。 - 02**您的后端** 确认用户有权观看后,向 DRM-X 请求播放授权。 - 03**DRM-X** 验证播放授权并处理 DRM 许可证请求。 - 04**播放器 + 设备** 使用设备的 DRM 系统获取许可证,并播放加密媒体。 您的后端判断用户是否有权观看,DRM-X 执行签名授权中的播放策略。加密媒体与 DRM 许可证通过各自的服务传送给播放器。 **从创建存储桶到成功上传** 创建 R2 存储桶,配置浏览器 CORS,选择公共 HTTPS 分发 URL,连接 DRM-X,然后上传并获取测试对象。不要在分发桶中存放原始视频或私人文档;只发布加密媒体及计划公开的资源。 公共分发允许通过 URL 获取对象字节;正确打包加密的媒体仍由 DRM 控制解密。CORS 是浏览器兼容规则,不提供授权。这里的真实 Console 截图已排除账号页头和个人标识信息。菜单名称可能随版本变化。 ## 1. 创建您的 R2 存储桶[#](#create-bucket) - 登录 Cloudflare 并选择将拥有该存储桶的账户。 - 打开 **Storage & databases → R2 Object Storage → Overview → Create bucket**。 - 输入唯一的存储桶名称,例如 `customer-drm-media-example`,并选择合适的位置或管辖区。本指南使用 **Standard** 存储类型,然后创建存储桶。 - 打开存储桶的**Settings**。记录存储桶名称、Cloudflare account ID 和**General → S3 API**端点。 默认管辖区的 API 端点为 `https://.r2.cloudflarestorage.com`。如果 Cloudflare 显示特定管辖区的主机名,请原样使用。在 DRM-X 中填写端点时,去掉末尾的 `/bucket-name`;存储桶名称需填写在单独的字段中。此 API 端点不能用作公共播放 URL。 ## 2. 创建仅限指定存储桶的凭据[#](#create-credentials) - 返回 R2 Overview,打开 **Manage API tokens**。选择 R2 account token;如果组织要求,也可使用 user token。 - 选择**Create API token**,为其指定一个可识别的名称,然后选择**Object Read & Write**。 - 选择**Apply to specific buckets only**并选择此存储桶。根据您的策略配置到期时间。对于本演练,请保留可选的 IP 过滤未设置。如果您的安全策略需要,请验证 DRM-X 服务器访问和从客户浏览器网络的直接上传。 - 创建 Token,并妥善记录用于 DRM-X 的 **Access Key ID** 和 **Secret Access Key**。 **使用 S3 凭据对** Cloudflare 单独提供的 Token value 不是 S3 Secret Access Key。DRM-X 不需要账号级管理 Token。请自行在 Cloudflare 配置 CORS 和域名。 ## 3. 选择公共分发 URL[#](#public-delivery) ![R2 Settings:在 Custom Domains 下添加,或在 Public Development URL 下启用。](https://docs.drm-x.com/assets/storage/r2-delivery.png)12**1 — 生产:** 添加自定义域。 **2 — 测试:** 启用公共开发 URL。 ### 方案 A:为生产环境连接自定义域名 - 拥有一个域,其 DNS 设置是在同一 Cloudflare 帐户中完成的。选择一个子域,例如 `media.example.com`。 - 在存储桶中打开 **Settings → Custom Domains → Add**。输入子域名,确认 DNS 变更,并通过此 R2 流程完成连接。 - 等待域名及 HTTPS 证书生效。分发 origin 为 `https://media.example.com`。 请勿创建指向 r2.dev 地址的 CNAME。使用 R2 的 Custom Domains 工作流程。当连接自定义域时,开发 URL 可以保持禁用状态。 ### 方案 B:启用 Cloudflare 提供的测试 URL - 打开 **Settings → Public Development URL → Enable**。 - 查看公共访问通知,根据要求输入 `allow` 并确认。 - 复制 Cloudflare 实际显示的`https://pub-….r2.dev`URL。不要从您的帐户 ID 或存储桶名称构建它。 r2.dev 端点受到速率限制并用于开发。使用自定义域来实现生产、缓存和 Cloudflare 安全功能。 ## 4.配置浏览器上传和播放 CORS[#](#configure-cors) ![R2 CORS Policy 面板,显示 Edit 按钮、允许的 origin、方法和请求头。](https://docs.drm-x.com/assets/storage/r2-cors.png)12**1:**新存储桶选择 Add CORS policy,已有策略则选择 Edit。**2:**确认保存的 origin、请求方法和请求头。截图仅展示针对 Console 的诊断规则;播放器网站应使用下方完整的两条规则。 - 打开 **Settings → CORS Policy → Add CORS policy**(或 **Edit**)。 - 将下面的 JSON 粘贴到编辑器中。将 `https://www.example.com` 替换为嵌入您的播放器的网站的来源。来源包括 HTTPS 和主机名,但没有页面路径,例如 /watch。 - 如果存储桶已有策略,请保留其他必要规则,然后选择 **Save**。 - 等待配置生效后重试上传。如果自定义域名缓存了旧的 CORS 响应头,请清除相关路径的缓存响应,然后再次测试。 ``` [ { "AllowedOrigins": [ "https://6.drm-x.com" ], "AllowedMethods": [ "PUT" ], "AllowedHeaders": [ "Content-Type", "x-amz-meta-drmx-sha256" ], "ExposeHeaders": [ "ETag" ], "MaxAgeSeconds": 3600 }, { "AllowedOrigins": [ "https://6.drm-x.com", "https://multi-drm.drm-x.com", "https://www.example.com" ], "AllowedMethods": [ "GET", "HEAD" ], "AllowedHeaders": [ "Range" ], "ExposeHeaders": [ "ETag", "Content-Length", "Content-Range", "Accept-Ranges" ], "MaxAgeSeconds": 3600 } ] ``` 第一条规则允许 DRM-X Console 发起签名 PUT 上传。第二条规则允许播放器网站和 DRM-X 测试页面发起 GET/HEAD 请求。R2 自定义域名使用存储桶的 CORS 策略。配置 CORS 不会授予匿名上传权限。 ### 生成您的 CORS 和匹配的 URL 字段 该工具在您的浏览器中运行。仅输入公共来源;它不要求访问密钥。 播放器网站的 origin请替换示例网址。多个 HTTPS origin 可用空格或逗号分隔。填写嵌入播放器的网站来源,不包含页面路径。工具会自动加入 DRM-X Console 和 Playback Lab。公共分发 origin请输入已连接的自定义域名、已启用的 r2.dev URL 或 CloudFront origin。此处不填写文件夹。存储文件夹(可选)生成配置 复制 CORS JSON ``` ``` Protected-content base path``Public URL prefix``示例对象键``完整 URL 示例`` ## 5. 将 R2 连接到 DRM-X 6.0[#](#connect-drmx) 打开[Cloud Storage→Connect storage](https://6.drm-x.com/console/cloud-storage)并选择**Cloudflare R2**。 | 字段 | 输入什么 | | --- | --- | | Display name | 便于识别的名称,例如 Production R2。 | | Bucket name | 确切的存储桶名称,不带 URL 或文件夹。 | | Cloudflare account ID | 拥有此存储桶的账户的 ID。 | | S3 API endpoint | 使用默认管辖区时可留空,也可填写账号或管辖区对应的端点;不要包含存储桶路径。 | | Protected-content base path | `protected`;如需上传到存储桶根目录,则留空。 | | Public URL prefix | `https://media.example.com/protected` 或您启用的 `https://pub-….r2.dev/protected` URL。 | | Access key ID / Secret access key | 步骤 2 中的 S3 凭证对。 | 示例使用名为 `protected` 的文件夹。存储桶名称不会自动成为文件夹。使用本指南的域名直接映射到存储桶方式时,Public URL prefix 必须包含同一存储文件夹,且只出现一次。 ``` Bucket: customer-drm-media-example Protected-content base path: protected Public URL prefix: https://media.example.com/protected File selected for upload: sample.encrypted.bin Object key in the bucket: protected/sample.encrypted.bin Preview URL: https://media.example.com/protected/sample.encrypted.bin ``` 如需上传到存储桶根目录,将 Protected-content base path 留空,Public URL prefix 只填写分发 origin。除非刻意将存储桶名称用作文件夹,否则不要追加它。使用此映射时保持 CloudFront Origin path 为空。 如需将其用于 CLI 默认上传,请选择 **Use as default CLI upload destination**,然后选择 **Save and verify**。凭据以加密形式存储,保存后不会返回。即使验证成功,也应继续进行实际上传测试。 ## 6. 上传文件并验证其是否有效[#](#test-upload) - 打开 [Cloud Storage](https://6.drm-x.com/console/cloud-storage),选择此存储目标并单击 **Verify location**。成功仅表示 DRM-X 服务器可以列出存储桶内容,不能证明写入权限、浏览器 CORS 或公共分发正常。 - 单击 **Upload encrypted files**,从已有 DRM-X 加密输出包中选择一个小的加密片段。如果没有现成输出包,可使用下方的一次性加密诊断文件。不要上传原始视频或私人文档。 - 等待成功消息。检查文件名和大小是否出现在 Cloud Storage 中。在提供商控制台中的 `protected/` 下找到相同的对象。 - 单击 **Preview URL**,并在浏览器无痕窗口中测试同一对象。无需登录 AWS 或 Cloudflare,文件应可下载或返回 HTTP 200。请测试实际对象;即使对象分发正常,域名根路径仍可能返回 403/404。 - 在播放器网站上检查跨源分发。浏览器 Network 面板中的 `Access-Control-Allow-Origin` 应与播放器页面的 origin 匹配。直接在地址栏下载文件不能验证 CORS;下方命令也可用于检查响应头。 - 测试结束后,仅删除本次创建的临时诊断对象。然后按照 [Desktop Packager 指南](https://docs.drm-x.com/zh-Hans/packaging/desktop),在 Package content 中选择此存储目标,并上传完整的加密输出包。手动上传单个文件不会注册 Published Content ID。 - 在 [Universal Playback Lab](https://multi-drm.drm-x.com/zh-Hans/player) 和您的播放器网站上测试已 Published 的内容。验证视频、音频、跳转及所需设备。能下载二进制文件,并不能证明 DRM 播放正常。 没有加密示例?在 Windows 创建一次性测试文件 在您控制的临时文件夹中的 Windows PowerShell 中运行此命令。它使用仅保存在内存中的一次性 AES 密钥对一条简短的非个人消息进行加密。输出是存储诊断,而不是可播放媒体;它不包含 DRM 内容密钥或客户数据。 ``` $samplePath = Join-Path (Get-Location) 'drmx-storage-check.encrypted.bin' if (Test-Path -LiteralPath $samplePath) { throw 'Choose a new folder; this test file already exists.' } $aes = [System.Security.Cryptography.Aes]::Create() try { $aes.GenerateKey() $aes.GenerateIV() $encryptor = $aes.CreateEncryptor() try { $bytes = [Text.Encoding]::UTF8.GetBytes('DRM-X disposable storage check') $encrypted = $encryptor.TransformFinalBlock($bytes, 0, $bytes.Length) [IO.File]::WriteAllBytes($samplePath, $encrypted) } finally { $encryptor.Dispose() } } finally { $aes.Dispose() } Get-Item -LiteralPath $samplePath | Select-Object Name, Length ``` 上传`drmx-storage-check.encrypted.bin`,验证其大小和 Preview URL,然后将其从存储桶中删除。 ``` curl.exe -I -H "Origin: https://www.example.com" "https://media.example.com/protected/sample.encrypted.bin" ``` 替换两个 URL。预计 HTTP 200 以及与您的播放器网站匹配的允许来源。对于范围传递,带有 `Range: bytes=0-15` 的 GET 请求应返回 HTTP 206 和有效的 Content-Range 标头。保留媒体 MIME 类型:DASH 清单使用 application/dash+xml,HLS 播放列表使用 application/vnd.apple.mpegurl,并且媒体文件必须使用其适当的媒体类型。 ## 7. 排查问题[#](#troubleshooting) | 结果 | 处理方法 | | --- | --- | | 验证通过;浏览器上传失败 | 检查浏览器 Console 和 Network 面板。允许来自 Console 确切 origin 的 PUT CORS,并允许 Content-Type 请求头。检查网络连接,重新尝试以取得新的预签名 URL。 | | 上传返回 403 | 检查对象写入权限、存储桶/文件夹范围、端点、区域、请求到期和时钟。请勿共享签名的上传 URL。 | | 上传成功;公共 URL 返回 403 | 检查是否已启用公共分发,以及域名或 CloudFront 分配是否已部署完成。 | | 公开 URL 返回 404 | 将完整的 URL 与确切的对象键进行比较。检查丢失或重复的文件夹和文件名大小写。 | | URL 可直接打开,但播放器获取失败 | 将播放器页面的 origin 加入 GET/HEAD CORS。检查 CDN 响应头,并清除相关路径的旧缓存响应。 | | 下载成功;播放失败 | 检查加密输出包的发布状态、manifest 路径、MIME 类型和 DRM 许可证授权。参见[播放故障排查](https://docs.drm-x.com/zh-Hans/troubleshooting/playback)。 | ## 官方参考文献[#](#references) - [创建 R2 存储桶](https://developers.cloudflare.com/r2/buckets/create-buckets/) - [R2 凭证和权限](https://developers.cloudflare.com/r2/api/tokens/) - [自定义域和 r2.dev](https://developers.cloudflare.com/r2/buckets/public-buckets/) - [R2 CORS 和缓存行为](https://developers.cloudflare.com/r2/buckets/cors/) 使用 AWS?按照[Amazon S3 和 CloudFront 设置](https://docs.drm-x.com/zh-Hans/storage/amazon-s3)。