You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用预签名URL改造hls.js视频分发方案及相关疑问

问题解答

方案可行性

完全可行。预签名URL是云存储服务的标准功能,可授权客户端在有限时间内直接访问私有存储资源,无需通过Vercel服务器中转,完全适配HLS播放场景。

能否减少Fast Origin Transfer流量

绝对可以。当前方案中,Vercel需要从存储桶拉取视频流再转发给客户端,这部分从存储桶到Vercel的流量就是Fast Origin Transfer。改成预签名URL方案后,客户端直接向存储桶发起请求,Vercel仅需处理生成预签名URL的轻量请求,不会再产生大量中转流量,能大幅降低这部分费用。

具体实现步骤

1. 后端修改:新增预签名URL生成接口

替换原有的视频转发接口,改为生成存储桶预签名URL的接口。以下以AWS S3兼容存储服务(如Cloudflare R2、AWS S3)为例:

import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

export async function GET(context: APIContext): Promise<Response> {
    const { video_url } = context.params;

    if (!video_url) {
        return new Response(JSON.stringify({ message: "Los campos son requeridos" }), { status: 400 });
    }

    try {
        // 初始化存储桶客户端(根据实际服务配置调整)
        const s3Client = new S3Client({
            region: import.meta.env.BUCKET_REGION,
            credentials: {
                accessKeyId: import.meta.env.BUCKET_ACCESS_KEY,
                secretAccessKey: import.meta.env.BUCKET_SECRET_KEY,
            },
            // Cloudflare R2需额外配置endpoint
            // endpoint: import.meta.env.BUCKET_ENDPOINT
        });

        // 生成有效期1小时的预签名URL
        const command = new GetObjectCommand({
            Bucket: import.meta.env.BUCKET_NAME,
            Key: video_url // 需与存储桶内文件路径一致
        });
        const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600 });

        return new Response(JSON.stringify({ signedUrl }), {
            status: 200,
            headers: {
                'Content-Type': 'application/json',
                'Cache-Control': 'public, max-age=300' // 缓存预签名结果5分钟
            }
        });
    } catch (error) {
        console.error('生成预签名URL失败:', error);
        return new Response('Internal Server Error', { status: 500 });
    }
}

2. 客户端修改:先获取预签名URL再播放

调整前端逻辑,先调用预签名接口拿到URL,再传给HLS播放器或设置视频源:

async function loadVideo(videoElement, video_url) {
    try {
        // 第一步:获取预签名URL
        const response = await fetch(`/api/videos/getSignedUrl/${video_url}`);
        if (!response.ok) throw new Error('获取预签名URL失败');
        const { signedUrl } = await response.json();

        // 第二步:使用预签名URL播放
        if (Hls.isSupported()) {
            const hls = new Hls();
            hls.attachMedia(videoElement);
            hls.on(Hls.Events.MEDIA_ATTACHED, () => hls.loadSource(signedUrl));
            
            // 可选:处理URL过期后的重试逻辑
            hls.on(Hls.Events.ERROR, (event, data) => {
                if (data.fatal && data.type === Hls.ErrorTypes.NETWORK_ERROR) {
                    loadVideo(videoElement, video_url);
                }
            });
        } else if (videoElement.canPlayType('application/vnd.apple.mpegurl')) {
            videoElement.src = signedUrl;
        }
    } catch (error) {
        console.error('加载视频失败:', error);
    }
}

// 调用示例
const video = document.getElementById('your-video-element');
loadVideo(video, 'your-video-path.m3u8');

关键注意事项

  • 预签名有效期:建议设置为1-2小时,平衡安全性与播放体验,避免过短导致播放中途URL过期。
  • HLS分片处理:若存储桶为私有,且m3u8内分片使用相对路径,可选择两种方案:
    1. 后端获取m3u8内容,将分片路径替换为预签名URL后返回(m3u8文件体积小,流量可忽略);
    2. 为每个分片单独生成预签名URL(需前端额外处理,请求量较大)。

内容的提问来源于stack exchange,提问作者Bruno Munné

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 18:35:02