从在一台机器上工作的浏览器下载 S3 图像并在另一台机器上给出 CORS 错误

Posted

技术标签:

【中文标题】从在一台机器上工作的浏览器下载 S3 图像并在另一台机器上给出 CORS 错误【英文标题】:Downloading S3 image from browser working on one machine and giving CORS error on another machine 【发布时间】:2019-03-18 20:21:06 【问题描述】:

我有一个 Angular2 应用程序,我正在尝试从 S3 下载一组图像并将它们放在一个 zip 文件中。我正在使用从https://gist.github.com/noelvo/4502eea719f83270c8e9获得的以下代码

dlImages(urlList, jobName) 

    var zip = new JSZip();
    var count = 0;
    var zipFilename = jobName.split(" ").join("_") + ".zip";
    var img = zip.folder("images");

    console.log(zipFilename);

    urlList.forEach(function (url, idx) 
        //filename and file type should be the same it is in s3
        var fileExtension = url.split('.').pop(-1);
        var realIdx = idx + 1;
        var filename = realIdx.toString().concat(".").concat(fileExtension);
        console.log(url);
        console.log(filename);

        JSZipUtils.getBinaryContent(url, function (err, data) 
            if (err) 
                throw err; // or handle the error
            
            img.file(filename, data, binary: true);
            count++;

            if (count == urlList.length) 
                zip.generateAsync(type: 'blob').then(function (content) 
                    FileSaver.saveAs(content, zipFilename);
                );
            
        );
    );

代码在 Heroku 应用程序上运行,奇怪的是它在我的开发机器(chrome 版本 68.0.3440.106)上按预期工作,但是它在另一台机器上给出了 CORS 错误(chrome 版本 69.0.3497.100)。具体的CORS错误是

Failed to load url.for.image.in.s3.jpg: No 'Access-Control-Allow-Origin' header is present on the requested resource.  Origin 'https://myherokuapp.herokuapp.com' is therefore not allowed access.

对于集合中的每个图像 url,都会引发上述错误。 我对存储桶的 CORS 政策是

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>https://*</AllowedOrigin>
    <AllowedOrigin>http://*</AllowedOrigin>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

另外,在我的 app.js 文件中,我有

app.use(function (req, res, next) 
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PATCH, DELETE, OPTIONS');
    next();
);

有谁知道为什么这个 CORS 政策会出现这个 CORS 错误?一个后续问题是为什么这可以在一台机器上运行,但不能在另一台机器上运行?

编辑:

以下是尝试下载图像时每台机器的响应标头的屏幕截图。

这是可以工作的机器的响应标头

这是不工作的机器的响应标头

很明显,不同之处在于不工作的机器的响应标头没有 ACCESS-CONTROL-ALLOW 字段,但我不知道为什么会这样。我会做一些研究,但如果有人知道这将非常有帮助。

第二次编辑:

这里还有不工作的机器的请求头

Origin: https://xxxxx.herokuapp.com

Referer: https://xxxxx.herokuapp.com/yyyyyyyy/5ac2635557c3f70014529d4d

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/69.0.3497.100 Safari/537.36

除了用户代理之外,正常工作的机器的请求标头是相同的。

【问题讨论】:

浏览器缓存?也许尝试清除浏览器缓存/强制重新加载 能否提供两台机器上浏览器控制台的请求/响应标头? 嘿,您能否也为这两个图像请求尝试添加请求标头?如果可以的话,文字会比图片更好。 嗯,这排除了我的理论,即触发问题响应的请求缺少 Origin 标头。如果我对此进行故障排除,我会从 Chrome DevTools 获取 curl 命令以获取“坏”机器上的网络请求(Network 选项卡 > 右键单击​​ > Copy > Copy as cURL),然后在两者上运行此命令“好”和“坏”机器,添加 -v 参数以显示标题。松散地说,如果对 curl 命令的响应具有 Access-Control-Allow-* 标头,那么服务器就可以了,您可以通过它隔离机器/浏览器。 哦,关于飞行前的话题,基于this,这些请求将是“简单的”,不会触发飞行前检查的要求。这与我在测试您的代码时看到的内容相吻合(即,每个图像只有 GET 请求)。 【参考方案1】:

尝试替换

<AllowedOrigin>https://*</AllowedOrigin>
<AllowedOrigin>http://*</AllowedOrigin>

<AllowedOrigin>*</AllowedOrigin>

【讨论】:

谢谢,但这并没有解决问题。我想我已经尝试了所有可以想象的 CORS 配置 :) 我倾向于认为这是某种奇怪的浏览器相关问题 我遇到了同样的问题。当我清除缓存后,问题就消失了。【参考方案2】:

通过将 CORS 配置添加到我的存储桶中删除了 CORS 错误,但仍然无法下载图像。

我尝试了不同的解决方案,但这些步骤对我有用。您应该尝试这些步骤。

1.在您的存储桶上添加 CORS 配置。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

2.crossorigin="anynymous" 添加到 img 标签

<img crossorigin="anonymous" id="media_img" src="example.jpeg">

3.JS代码

  $('#media_img').on('click', () => 
    downloadImage();
  )
 
  function toDataURL(url) 
    return fetch(url).then((response) => 
      return response.blob();
    ).then(blob => 
      return URL.createObjectURL(blob);
    );
  

  async function downloadImage() 
    const a = document.createElement('a');
    a.href = await toDataURL($('#media_img').attr('src'));
    a.download = 'example.jpeg';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  

【讨论】:

以上是关于从在一台机器上工作的浏览器下载 S3 图像并在另一台机器上给出 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在一台机器上保存张量板投影仪检查点文件并在另一台机器上打开?

php 在一台机器上解析失败,但在另一台机器上解析失败

为啥我的 Perl 程序在一台机器上得到污染警告,而在另一台机器上却没有?

C++:Cookie 不存储在一台机器上,而是存储在另一台机器上

React/webpack - 如何在一台服务器上托管 React 应用程序,在另一台服务器上托管图像/字体?

为啥 load_ps() 可以在一台 PC 上工作,而不能在另一台 PC 上工作?