Video.js - HLS => 没有“Access-Control-Allow-Origin”标头 [S3,CloudFront]

Posted

技术标签:

【中文标题】Video.js - HLS => 没有“Access-Control-Allow-Origin”标头 [S3,CloudFront]【英文标题】:Video.js - HLS => No 'Access-Control-Allow-Origin' header [S3, CloudFront] 【发布时间】:2021-10-01 05:04:13 【问题描述】:

在我的应用程序中使用 video.js 插件播放 HLS 视频时遇到问题。 我有一个 HLS 视频(.m3u8,.ts)的 S3 存储,并且它连接到云端。视频在 safari 上运行,但在 chrome 上运行不正常。仅当我重新加载页面(删除缓存,cookie,...)时,它们才在 chrome 上工作。

我的配置:

Video.JS:

videojs.Hls.xhr.beforeRequest = function (options) 
      options.headers = 
        "Access-Control-Allow-Origin": "*",
      ;
      return options;
    ;

S3 存储桶 CORS:

[
    
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "PUT",
            "POST",
            "HEAD"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "ETag",
            "Access-Control-Allow-Origin",
            "Connection",
            "Content-Length"
        ],
        "MaxAgeSeconds": 3000
    
]

CloudFront:

【问题讨论】:

Access-Control-Allow-Origin 不应作为请求标头发送。参见例如***.com/a/19939041/740233 用于在 S3 上设置 CORS。 @misterben 如果你的意思是在 Video.js 中,它被放置在那里作为最后一次尝试修复它,所以即使没有来自视频插件的请求,它也无法工作。 【参考方案1】:

我遇到了类似的问题。就我而言,一些文件已成功接收,但其他文件(在同一个目录中,通过相同机制同时上传)引发了 CORS 错误。 经过几天的调查,我修复了它(我希望)。我将我的发现留给未来的研究人员。

CORS 支持是在 S3 中实现的,互联网上有很多关于如何配置它的信息。

当请求 CloudFront 链接时,AWS 检查 CloudFront 缓存中是否存在请求的对象。如果是,CloudFront 会返回它。如果没有,CloudFront 从源(在我的例子中是 S3)请求它,缓存它,然后返回。

当请求 S3 链接并且请求中有 origin 标头时,S3 返回带有 access-control-allow-origin 标头的文件,否则,access-control-allow-origin 不会添加到响应标头中。

当 CloudFront 从源 (S3) 请求文件时,它可以将请求标头(与文件请求一起发送)传输到源 (S3)。这就是为什么您必须将 origin 标头(和任何其他标头)添加到“选择要包含在缓存键中的标头”。在这种情况下,如果对 CloudFront 的请求包含 origin 标头,它也会被发送到 S3。否则,CloudFront 将向 S3 请求不带 origin 标头的文件,S3 将返回不带 access-control-allow-origin 标头的文件,不带标头的文件将被缓存并返回给浏览器(CORS 错误)。 headers

现在缓存和原始设置下有 2 个选项:“缓存策略和原始请求策略(推荐)”和“旧版缓存设置”(似乎之前没有选项,只有“旧版缓存设置”中的设置)存在)。在“缓存策略和源请求策略(推荐)”下有“缓存策略”和“源请求策略 - 可选”部分。如果设置了预定义的推荐策略,则 origin 标头(和其他)是为“源请求策略 - 可选”预定义的,但不是为“缓存策略”预定义的。老实说,我不了解每个的确切含义,但似乎旧版“选择要包含在缓存键中的标头”现在分为 2 个部分。如果您使用“缓存策略和源请求策略(推荐)”而不是“旧版缓存设置”,则必须创建一个新的缓存策略(推荐的副本)并添加标头(与 CORS-S3Origin 策略中的相同)。 recomended settingscors-s3origincachingoptimised

就我而言,如果第一次从移动应用程序请求文件,则请求没有origin 标头。这就是为什么 S3 在没有 access-control-allow-origin 标头的情况下返回它们,并且它们在没有标头的情况下缓存在 CloudFront 中。由于 CORS 错误(“No 'Access-Control-Allow-Origin'...”),所有带有 origin 标头的下一个请求(浏览器总是在您从 js 发出请求时添加此标头)失败。

可以为从 CloudFront 到 S3 的请求添加自定义标头(来源 -> 编辑特定来源 -> 添加自定义标头)。如果您不关心用户从何处请求您的文件,您可以在此处添加 origin 标头并将其设置为任何值。在这种情况下,对 S3 的所有请求都将具有 origin 标头。 custom header

有很多 Clo​​udFront 边缘站点。它们每个都有自己的缓存。用户将从最近的一个接收文件。这就是为什么有些用户可能会成功接收文件,但其他用户会收到 CORS 错误。

CloudFront 响应标头中有一个 x-cache 标头。该值可以是“Miss from cloudfront”(缓存中没有请求文件)或“Hit from cloudfront”(从缓存返回的文件)。因此,您可以查看您的请求是否是第一个到特定边缘位置的请求(如果您想尝试,请在 devtools 中禁用浏览器缓存)。但有时它表现得像随机的),我不知道为什么。

看起来即使是同一个边缘位置也可以为不同的客户端提供不同的缓存。我不知道它基于什么,但我尝试使用浏览器、Postman 和 curl 进行试验,并得到了下一个结果(我已经尝试过很多次不同的文件和不同的排序 - 来自curl 看不到为浏览器和 Postman 创建的缓存,反之亦然):

    来自浏览器的请求返回“Miss from cloudfront”; 来自浏览器的请求返回“Hit from cloudfront”; 邮递员的请求返回“来自云端的命中”; 来自 curl 的请求返回“Miss from cloudfront”; 来自 curl 的请求返回“来自云端的命中”。

由于 AWS 文档对这个问题的态度很差,而且支持人员只建议阅读文档,因此我不确定我的部分结论。我就是这么想的。

【讨论】:

以上是关于Video.js - HLS => 没有“Access-Control-Allow-Origin”标头 [S3,CloudFront]的主要内容,如果未能解决你的问题,请参考以下文章

Video.js HTML5播放器可以播放m3u8播放列表(HLS)?

解决问题video.js 播放m3u8格式的文件,根据官方的文档添加videojs-contrib-hls也不行的原因解决了

直播 - HLS + RTSP 使用 Video.js (Wowza 服务器)

vue播放video插件vue-video-player实现hls, rtmp播放全过程

vue.js+video.js+videojs-contrib-hls支持PC端播放m3u8格式的视频

video.js 视频截图录制自定义全屏,hlsflvmp4视频播放