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

Laravel+Video.js播放m3u8(HLS)时.ts分片触发CORS跨域报错

问题根因

跨域拦截本质是三个配置错误共同导致:

  • 前端配置冲突:错误给XHR请求添加了Access-Control-Allow-Origin头——这个是服务端返回的响应头,前端请求携带该头会直接触发预检请求失败;同时开启了withCredentials: true和crossOrigin: "use-credentials",但后端CORS配置未开启凭据支持,和通配符允许源规则互斥。
  • CORS配置覆盖不全:现有CORS规则仅匹配api/*路径,但ts分片默认走/storage/开头的静态文件路由,完全不经过CORS中间件,不会返回跨域响应头,浏览器直接拦截响应。
  • HLS地址解析逻辑错误:m3u8索引文件走/api/video-get路由(能正常返回跨域头),但ts分片地址被解析为静态storage路径,和索引文件不同源且无跨域头,才会出现m3u8加载正常、ts分片被拦截的现象。
分步修复方案

第一步:修正前端播放器配置

删除无效配置、错误请求头和冲突的跨域参数,修正后代码如下:

import React, { useEffect, useRef, useState } from "react";
import videojs from "video.js";
import "video.js/dist/video-js.css";

const Video = () => {
  const videoNode = useRef(null);
  const [player, setPlayer] = useState(null);
  useEffect(() => {
    if (videoNode.current) {
      const _player = videojs(videoNode.current, {
        fill: true,
        fluid: true,
        autoplay: true,
        controls: true,
        preload: "metadata",
        crossOrigin: "anonymous",
        sources: [
          {
            src: "http://127.0.0.1:8000/api/video-get/video.m3u8",
            type: "application/x-mpegURL",
          },
        ],
      });
      setPlayer(_player);
      return () => {
        if (player !== null) {
          player.dispose();
        }
      };
    }
  }, []);

  return (
    <div data-vjs-player>
      <video ref={videoNode} className="video-js"></video>
    </div>
  );
};

export default Video;

注意:如果后续需要带cookie鉴权,就不能用*作为允许源,必须明确指定前端域名,同时把后端supports_credentials设为true,两个配置二选一不能冲突。

第二步:修正Laravel CORS配置覆盖范围

把storage静态资源路径加入跨域匹配规则,修改config/cors.php:

return [
    // 新增storage路径匹配,覆盖ts分片请求
    'paths' => ['api/*', 'sanctum/csrf-cookie', 'storage/*'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['*'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => false,
];

修改完成后执行php artisan config:clear清除配置缓存。

第三步:修正HLS资源路由逻辑

不要把ts分片地址指向静态storage路径,统一让所有HLS资源(m3u8索引、ts分片)走同一套API路由,确保所有请求都经过CORS中间件处理,修改视频读取路由代码:

Route::get('/video-get/{media}', function ($media) {
    // 处理m3u8索引文件
    if (str_ends_with($media, '.m3u8')) {
        return FFMpeg::dynamicHLSPlaylist()
            ->fromDisk('public')
            ->open($media)
            ->setPlaylistUrlResolver(function ($playlist) {
                return url('/api/video-get/' . $playlist);
            })
            // ts分片也指向当前API路由,不返回静态storage地址
            ->setMediaUrlResolver(function ($mediaFile) {
                return url('/api/video-get/' . $mediaFile);
            });
    }

    // 处理ts分片,返回二进制流并自动附带CORS头
    return Storage::disk('public')->response($media);
// 加正则匹配兼容带多级目录的分片路径,避免404
})->where('media', '.*\.(m3u8|ts)$');

第四步(可选兜底):Web服务器层直接加跨域头

如果生产环境不想让ts分片请求走Laravel框架,直接用Nginx/Apache处理静态资源,可以在Web服务器配置中直接给HLS相关文件加跨域头,Nginx配置参考:

location ~* \.(m3u8|ts)$ {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods 'GET, OPTIONS';
    add_header Access-Control-Allow-Headers '*';
    if ($request_method = 'OPTIONS') {
        return 204;
    }
}
验证标准

修改完成后清除浏览器缓存重新测试:

  • m3u8索引和ts分片请求的响应头都携带Access-Control-Allow-Origin: *
  • ts分片响应体大小正常,不为空
  • 播放器可正常播放、拖动进度,控制台无跨域报错

内容的提问来源于stack exchange,提问作者Rawa Hamid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 07:03:27