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

6
我有一个S3存储桶作为源,以及一个CloudFront分发服务从中流式传输音视频。 我还有一个EC2实例,从测试域名提供Web页面,并使用videojs作为测试来显示视频。
如果我启动VLC媒体播放器并使用CloudFront URL查看视频,则可以同时看到和听到媒体。 因此,如果我不必处理CORS,这个配置可以提供内容。
但是,当我尝试从我的EC2实例的网页中查看内容时,遇到了CORS问题。
使用Firefox并观察开发工具中的网络选项卡,我发现Firefox无问题地获取了初始的.mp4 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

...我发现缺少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==
< 

请注意,在OPTIONS请求中缺少了“access-control-allow-origin: *”标头。它实际上已经获取了内容。因此,我认为唯一阻止这个问题的是缺少OPTIONS查询的access-control-allow-origin标头。除非我遗漏了什么(在这一点上可能是可能的...我已经花了太多时间在这个问题上,并且可能会从看到解决方案的角度狭窄)。
CloudFront分发的行为设置允许GET、HEAD和OPTIONS方法,并启用了“缓存HTTP方法”的OPTIONS复选框,因此应该缓存OPTIONS。
分发行为的缓存策略包括以下标头:
- Origin - Access-Control-Request-Method - Access-Control-Allow-Origin - Access-Control-Request-Headers
所有cookie都已启用(尽管这对本情况无关紧要)。
TTL设置的最小值为0,最大值为31536000,默认值为86400,但我怀疑这并不重要。
分发行为的Origin请求策略包括以下标头:
- Origin - Access-Control-Request-Headers - Access-Control-Request-Method
这是CORS-S3Origin受控策略。
分发行为的响应标头策略启用了“配置CORS”,具有以下内容:
- Access-Control-Allow-Origin:所有来源 - Access-Control-Allow-Headers:所有标头 - Access-Control-Allow-Methods:所有HTTP方法 - Access-Control-Expose-Headers:所有标头 - Access-Control-Max-Age:600 - 检查覆盖来源
S3存储桶在其权限选项卡中具有CORS设置。
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "HEAD"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "ETag",
            "Access-Control-Allow-Origin",
            "Connection",
            "Content-Length"
        ],
        "MaxAgeSeconds": 3000
    }
]

该网页使用以下代码(包括少量 PHP 代码)来播放内容(在 script 标签中):
        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();

在文档中有以下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>

我还使用这些设置使分发的缓存内容无效,并等待了24小时后再次尝试查看,但我仍然无法通过videojs播放器流式传输视频。我已经用尽了我的谷歌技巧,现在转向你,亲爱的读者,请求帮助。我该如何说服videojs播放这个在VLC中完美播放的内容?


小提示...我可以使用Chrome的--disable-web-security参数浏览到页面并查看内容,但这不是我想要的工作方式。 - Joseph Van Riper
另外一点……我确保在VLC内观看视频后使缓存无效。但是我仍然在curl中看到了有问题的行为。 - Joseph Van Riper
嗯...我猜AWS可能有某种错误或问题,因为我无法看出这将如何起作用。相反,我将使用此堆栈并根据我的需求进行修改...这有点可惜:https://aws.amazon.com/solutions/implementations/video-on-demand-on-aws/ - Joseph Van Riper
最后,我最终选择了使用AWS的堆栈来生成Lambda函数并采用这种方法,而不是之前的方案。我怀疑AWS最近的CORS支持并没有按照预期工作。 - Joseph Van Riper
你解决了这个问题吗?我也遇到了同样的问题。 - royallife
很遗憾,我不得不想出一些完全不同的方法,但始终没有达到我的目标。 - Joseph Van Riper
1个回答

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

CloudFront CORS


哦,有意思...我应该尝试组合一些东西来测试这个。也许我需要再次尝试这种事情。 - Joseph Van Riper
是的,对我来说,在存储桶设置的“跨源资源共享”部分中设置“ExposeHeaders”值似乎是缺失的。此后,它会在响应中发送“access-control-allow-origin”头。有点令人困惑,因为我原本以为这是在CloudFront响应策略中处理的。 - Craig van Tonder
你在 @CraigvanTonder 那里将 "ExposeHeaders" 值设置为了什么? - IARI
@IARI 这取决于您自己的用例,您需要指定哪些值。话虽如此,如果您希望将Access-Control-Allow-Origin发送回客户端,则似乎确实需要在ExposeHeaders数组中指定它。对于我的用例:"ExposeHeaders": [ "ETag", "Access-Control-Allow-Origin", "Connection", "Content-Length" ] - Craig van Tonder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接