无中间服务器时如何从ReactJS直接上传视频至Azure Media Service
实现思路
核心逻辑:Azure Media Service(AMS)的视频资产底层存储本质是关联的Azure Blob存储容器,无需通过AMS管理SDK上传视频内容,仅需后端提前生成带临时写入权限的SAS令牌,前端直接将视频上传到对应Blob容器即可,全程视频流不经过服务端中转。
具体步骤:
- 服务端(必须后端执行,避免AMS密钥泄露)预创建AMS空资产,调用存储接口生成该资产对应Blob容器的限时SAS令牌,仅开放写入权限,有效期建议控制在1~2小时
- 服务端将SAS拼接后的上传地址返回给前端React组件
- 前端使用Azure Blob存储客户端SDK,直接将视频文件上传到该SAS地址
- 上传完成后前端通知服务端,由服务端触发AMS后续的编码、发布、流媒体处理等操作
代码示例
后端Node.js示例(仅在服务端运行,禁止放到前端)
首先安装依赖:
npm install @azure/arm-mediaservices @azure/identity @azure/storage-blob
核心代码:
const { AzureMediaServices } = require("@azure/arm-mediaservices"); const { DefaultAzureCredential } = require("@azure/identity"); const { BlobServiceClient, generateBlobSASQueryParameters, BlobSASPermissions } = require("@azure/storage-blob"); // AMS配置参数,存在服务端环境变量里 const subscriptionId = process.env.AZURE_SUBSCRIPTION_ID; const resourceGroup = process.env.AZURE_RESOURCE_GROUP; const amsAccountName = process.env.AZURE_MEDIA_ACCOUNT_NAME; const storageAccountName = process.env.AZURE_STORAGE_ACCOUNT_NAME; const storageAccountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY; async function getVideoUploadSas(fileName) { // 1. 初始化AMS客户端,创建空资产 const credential = new DefaultAzureCredential(); const amsClient = new AzureMediaServices(credential, subscriptionId); const asset = await amsClient.assets.createOrUpdate(resourceGroup, amsAccountName, `asset-${Date.now()}`, {}); // 2. 生成资产对应Blob容器的SAS令牌 const containerName = asset.container; const blobServiceClient = new BlobServiceClient(`https://${storageAccountName}.blob.core.windows.net`, credential); const containerClient = blobServiceClient.getContainerClient(containerName); const sasToken = generateBlobSASQueryParameters({ containerName, blobName: fileName, permissions: BlobSASPermissions.parse("w"), // 仅开放写入权限 expiresOn: new Date(Date.now() + 3600 * 1000), // 1小时有效期 }, storageAccountKey).toString(); // 3. 返回前端需要的上传地址和资产ID return { uploadUrl: `${containerClient.getBlockBlobClient(fileName).url}?${sasToken}`, assetId: asset.id }; }
前端React组件示例
安装客户端Blob SDK:
npm install @azure/storage-blob
核心代码:
import { useState } from 'react'; import { BlockBlobClient } from '@azure/storage-blob'; const VideoUploader = () => { const [uploadProgress, setUploadProgress] = useState(0); const [isUploading, setIsUploading] = useState(false); const handleFileSelect = async (e) => { const file = e.target.files[0]; if (!file || file.type.indexOf('video/') === -1) return; setIsUploading(true); setUploadProgress(0); try { // 1. 从后端获取上传SAS地址 const res = await fetch('/api/get-upload-sas', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ fileName: file.name }) }); const { uploadUrl, assetId } = await res.json(); // 2. 直接上传到Blob存储 const blockBlobClient = new BlockBlobClient(uploadUrl); await blockBlobClient.uploadData(file, { blockSize: 4 * 1024 * 1024, // 4MB分片,适合大视频 concurrency: 5, onProgress: (progress) => { const percent = Math.round((progress.loadedBytes / file.size) * 100); setUploadProgress(percent); } }); // 3. 通知后端上传完成,触发后续AMS处理 await fetch('/api/on-upload-complete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ assetId, fileName: file.name }) }); alert('视频上传成功'); } catch (err) { console.error('上传失败', err); alert('上传失败,请重试'); } finally { setIsUploading(false); } }; return ( <div> <input type="file" accept="video/*" onChange={handleFileSelect} disabled={isUploading} /> {isUploading && <div>上传进度:{uploadProgress}%</div>} </div> ); }; export default VideoUploader;
注意事项
- 必须在AMS关联的存储账户中配置CORS规则,允许前端域名的OPTIONS、PUT请求,否则会出现跨域错误
- SAS令牌仅开放最小必要权限(仅写入)和最短有效期,避免被滥用
- 大视频上传时SDK会自动处理断点续传、分片上传,无需额外开发
- AMS的编码、发布、DRM配置等管理操作必须由后端调用AMS接口执行,禁止将AMS管理密钥暴露到前端
内容的提问来源于stack exchange,提问作者Omtechguy
相关产品推荐
相关产品推荐

