CloudFront、S3、CORS、OPTIONS 方法“缺少允许来源”

Jos*_*per 6 amazon-s3 amazon-web-services cors amazon-cloudfront

我有一个 S3 存储桶作为源,还有一个 CloudFront 发行版,从中提供流媒体 a/v。

我还有一个 EC2 实例,从测试域提供网页,该测试域使用 videojs 显示视频作为测试。

如果我启动 VLC 媒体播放器并使用 CloudFront URL 观看视频,我会看到并听到媒体。因此,如果我不必处理 CORS,则此配置确实可以满足内容。

但是,当我尝试从 EC2 实例的网页查看内容时,我遇到了 CORS 问题。

使用 Firefox 并观察开发人员工具中的“网络”选项卡,我发现 Firefox 可以毫无问题地获取初始 .mpd URL。但是,后续文件(*.cmfv、*.cmfa,全部嵌入在 .mpd XML 中)在预检检查(OPTIONS 方法调用)中显示“CORS 缺少允许来源”。引发 OPTIONS 请求的 GET 请求会出现 NS_ERROR_DOM_BAD_URI 错误,并且永远不会发送。

使用curl,我模仿了来自Firefox的请求:

curl -H "origin: https://my.happy.url" -H "referer: https://my.happy.url" -H "Access-Control-Request-Headers: range" -H "Access-Control-Request-Method: GET" -X OPTIONS -v https://gobbledygook.cloudfront.net/content/10%20Minutes%20Of%20Coding%20Torture_6.cmfv

我得到这样的回应:

> OPTIONS /content/10%20Minutes%20Of%20Coding%20Torture_6.cmfv HTTP/2
> Host: gobbledygook.cloudfront.net
> user-agent: curl/7.79.1
> accept: */*
> origin: https://my.happy.url
> referer: https://my.happy.url
> access-control-request-headers: range
> access-control-request-method: GET
> 

* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200 
< content-length: 0
< date: Tue, 16 Nov 2021 19:25:54 GMT
< server: AmazonS3
< vary: Origin,Access-Control-Request-Headers,Access-Control-Request-Method
< x-cache: Hit from cloudfront
< via: 1.1 aaaaaaaiiiiiiiggggghhhhh.cloudfront.net (CloudFront)
< x-amz-cf-pop: IUD69-C2
< x-amz-cf-id: pHptphptmQ2lILrG9dpKVZIXT7Dhm_HSDVnBPijf7KcS7ZsLkKA==
< age: 1603
< 
* Connection #0 to host gobbledygook.cloudfront.net left intact

Run Code Online (Sandbox Code Playgroud)

...我发现明显缺乏 Access-Control-Allow-Origin,这是我在 JavaScript 控制台日志记录中看到的抱怨。

然而,如果我使用curl 来模仿最初的GET 请求:

curl -H "origin: https://my.happy.url" -H "referer: https://my.happy.url" -H "range: bytes=658-4657" -v https://gobbledygook.cloudfront.net/content/10%20Minutes%20Of%20Coding%20Torture_6.cmfv

...我明白了:

> Host: gobbledygook.cloudfront.net
> user-agent: curl/7.79.1
> accept: */*
> origin: https://my.happy.url
> referer: https://my.happy.url
> range: bytes=658-4657
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 206 
< content-type: video/mp4
< content-length: 4000
< date: Wed, 17 Nov 2021 11:54:27 GMT
< last-modified: Wed, 10 Nov 2021 15:36:31 GMT
< etag: "a2155000203fcc7e173acdc053a75cd1"
< x-amz-version-id: mfCll81lDxmeTyDIYmsoKFINElW2AmE1
< accept-ranges: bytes
< server: AmazonS3
< vary: Origin,Access-Control-Request-Headers,Access-Control-Request-Method
< content-range: bytes 658-4657/8320198
< access-control-allow-origin: *
< x-cache: Miss from cloudfront
< via: 1.1 aaaaaaaiiiiiiiggggghhhhh.cloudfront.net (CloudFront)
< x-amz-cf-pop: IAD66-C2
< x-amz-cf-id: hd-iBmLikeSmoNEYznT3SoWKNDERIGHE-gtjH2U3JlQDlwccL6SdQ==
< 
Run Code Online (Sandbox Code Playgroud)

请注意包含access-control-allow-origin: *OPTIONS 缺少的标头。它确实获取了内容。因此,在我看来,唯一阻碍这一点的是 OPTIONS 查询缺少 access-control-allow-origin 标头。除非我遗漏了一些东西(在这一点上这是可能的......我可能在这方面花费了太多时间,并且可能会因为看到解决方案而目光短浅)。

CloudFront 发行版的行为设置为允许 GET、HEAD 和 OPTIONS 方法,并且启用了“缓存 HTTP 方法”OPTIONS 复选框,因此它应该缓存 OPTIONS。

分发行为的缓存策略包括以下标头:

  • 起源
  • 访问控制请求方法
  • 访问控制允许来源
  • 访问控制请求标头

并且所有 cookie 均已启用(这对于这种情况并不重要)。

TTL 设置的最小值为 0,最大值为 31536000,默认值为 86400,但我怀疑这是否重要。

分发行为的源请求策略包括以下标头:

  • 起源
  • 访问控制请求标头
  • 访问控制请求方法

这是 CORS-S3Origin 托管策略。

分配行为的响应标头策略已启用“配置 CORS”,其中包含以下内容:

  • Access-Control-Allow-Origin:所有来源
  • Access-Control-Allow-Headers:所有标头
  • Access-Control-Allow-Methods:所有 HTTP 方法
  • Access-Control-Expose-Headers:所有标头
  • 访问控制最大年龄:600
  • 原点覆盖已检查

S3 存储桶的“权限”选项卡中有 CORS 设置:

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "HEAD"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "ETag",
            "Access-Control-Allow-Origin",
            "Connection",
            "Content-Length"
        ],
        "MaxAgeSeconds": 3000
    }
]
Run Code Online (Sandbox Code Playgroud)

该网页使用以下代码(带有一点PHP)来播放内容(在脚本标签中):

        const dashjsCallback = (player, mediaPlayer) => {
            if (videojs && videojs.log) {
                mediaPlayer.getDebug().setLogTimestampVisible(false);
            }
        };

        videojs.Html5DashJS.hook('beforeinitialize', dashjsCallback);

        const el = document.getElementsByTagName('video')[0];

        const manifest = "/content/<?php echo $policy_stream_name ?>";
        const mimeType = "application/dash+xml";

        const player = videojs(el, {
            "controls":true,
            "autoplay":true,
            "preload":"auto",
            "fluid":"true",
        });
        player.src({
            src: 'https://gobbledygook.cloudfront.net' + manifest,
            type: mimeType,
        });
        player.play();
Run Code Online (Sandbox Code Playgroud)

文档中包含以下 HTML:

    <video 
        id="my-video"
        class="video-js vjs-default-skin"
        controls
        preload="auto"
        height="480"
        data-setup="{}"
        crossorigin="anonymous"
    >
        <p class="vjs-no-js">This video requires JavaScript.</p>
    </video>
Run Code Online (Sandbox Code Playgroud)

我还使用这些设置使发行版的缓存内容失效,并等待了 24 小时才再次尝试查看,但我仍然无法通过 videojs 播放器流式传输视频。我已经用尽了我的谷歌功能,现在向你,温柔的读者寻求帮助。我如何说服 videojs 播放在 VLC 中完美播放的内容?

roy*_*ife 0

我通过在 CloudFront 中设置 CORS 以及设置 Bucket CORS 解决了这个问题。我的 Bucket CORS 已设置但不起作用,您还需要为 CloudFront CORS 设置 CORS。在这里您可以找到对我有帮助的解决方案。

CloudFront CORS