如何让HLS.js从服务端拉取数据 解决blob前缀视频资源路径无法访问问题
问题根因
你通过Blob URL加载m3u8清单时,hls.js会将Blob URL作为基准路径拼接所有相对路径的TS分片地址,因此出现了blob前缀的错误请求。以下是3种可行的实现方案:
方案1:服务端预处理m3u8分片路径(推荐,改动最小)
直接在PHP读取m3u8内容时,把所有分片的相对路径替换为指向video.php的绝对路径,hls.js解析后会直接请求你指定的接口,无需修改前端逻辑:
<?php // 读取原始m3u8内容 $m3u8Content = file_get_contents('./your_manifest_path.m3u8'); // 替换所有.ts后缀的分片路径为video.php接口地址,匹配规则可根据你的实际路径调整 $domain = 'https://<your domain>'; $processedContent = preg_replace_callback('/([a-zA-Z0-9_\-]+\.ts)/', function($matches) use ($domain) { return "{$domain}/video.php?file={$matches[1]}"; }, $m3u8Content); // 返回给前端 $res['manifest'] = $processedContent; echo json_encode($res); ?>
- 优点:无需修改前端hls.js逻辑,兼容性最好,也方便服务端统一做鉴权、流量控制。
方案2:前端通过hls.js配置拦截所有请求
无需修改服务端m3u8处理逻辑,通过hls.js内置的xhrSetup配置拦截所有请求,统一转发到video.php接口:
var manifest = res["manifest"]; var blob = new Blob([manifest]); // 初始化时传入xhrSetup配置 var hls = new Hls({ xhrSetup: function(xhr, url) { // 匹配所有带blob前缀的分片请求 if (url.startsWith('blob:')) { // 提取真实的资源路径,可根据你的实际路径规则调整提取逻辑 const realFilePath = url.replace('blob:https://<your domain>/', ''); // 替换为video.php接口地址 const targetUrl = `https://<your domain>/video.php?file=${encodeURIComponent(realFilePath)}`; // 重写请求地址 xhr.open('GET', targetUrl, true); // 如果需要带cookie或者自定义header可以在这里加 // xhr.withCredentials = true; } } }); var url = URL.createObjectURL(blob); hls.loadSource(url); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, function() { video.load(); });
- 优点:前端完全控制请求逻辑,不需要改动服务端已有接口。
方案3:省略Blob中转步骤,直接加载PHP接口地址
完全去掉前端先拉m3u8转Blob的逻辑,直接给hls.js传入返回m3u8的PHP接口地址,后续所有分片请求可配合xhrSetup统一转发到video.php:
var hls = new Hls({ xhrSetup: function(xhr, url) { // 只处理TS分片请求,跳过m3u8本身的请求 if (url.endsWith('.ts')) { const fileName = url.split('/').pop(); const targetUrl = `https://<your domain>/video.php?file=${encodeURIComponent(fileName)}`; xhr.open('GET', targetUrl, true); } } }); // 直接加载返回m3u8内容的PHP接口 hls.loadSource('https://<your domain>/get_m3u8.php?vid=xxx'); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, function() { video.play(); });
对应的get_m3u8.php示例:
<?php // 做参数校验、鉴权逻辑 $vid = $_GET['vid']; // 注意做路径安全校验,防止目录遍历 $m3u8Path = "./videos/{$vid}/index.m3u8"; if (!file_exists($m3u8Path) || !str_starts_with(realpath($m3u8Path), __DIR__ . '/videos/')) { http_response_code(403); exit; } header('Content-Type: application/vnd.apple.mpegurl'); header('Access-Control-Allow-Origin: *'); echo file_get_contents($m3u8Path); ?>
- 优点:省去Blob中转的冗余逻辑,全链路请求都可在服务端做管控。
安全提示
所有接收文件路径参数的PHP接口,必须做路径合法性校验,限制只能读取指定目录下的资源,避免用户传入../等路径实现目录遍历,读取到敏感文件。
内容的提问来源于stack exchange,提问作者Wilson Suwei
相关产品推荐
相关产品推荐

