如何使用html2Canvas和AWS S3图像处理CORS?

时间:2017-02-16 01:29:02

标签: javascript canvas amazon-s3

我知道之前已经提出了类似的问题,但我仍然无法使其发挥作用。我有一个div,其中包含从AWS s3中的存储桶加载的图像,它们完全没有问题。

现在我希望能够将jpeg保存为特定div中的任何内容(如截取屏幕截图),插件html2canvas有助于此。问题是,当我尝试实际保存它(或者只是立即显示这种屏幕截图的结果)时,我遇到了这些问题:

  • 画布受污染=>我在插件中设置allowTaint: true但它会抛出此错误,因此我禁用了它并且错误消失了。我将useCORS设置为true,但允许来自其他来源的图片。

  • CORS政策阻止了对图片的访问

为了解决这个问题,我在我的AWS S3存储桶上设置了CORS,但这似乎不起作用(或者它部分工作)。我注意到,当插件使用它们生成jpeg时,这些图像的响应头没有CORS元数据。然后我尝试在crossOrigin="anonymous"内的那些图像中设置div,但它会立即抛出一个CORS错误,这应该不会发生,因为AWS存储桶的设置如下:

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

我没有关于如何使这项工作的选项。如何从这里开始的任何想法将非常感激。

编辑:更多细节,我使用React并从服务器检索图像网址。这意味着,一旦我得到这个网址数组,我就会生成:

<div>
  { urls.map(url => <img src={url} alt="some alt" />) }
</div>

如果我添加crossOrigin="anonymous",我会收到CORS错误。如果我将其删除,则显示图像,但是当试图生成“屏幕截图”时,html2canvas插件也会引发CORS错误。

有关HTTP请求的更多详细信息。所以我第一次在div内加载图像时,这就是响应标题:

Accept-Ranges:bytes
Access-Control-Allow-Methods:GET
Access-Control-Allow-Origin:*
Cache-Control:max-age=2592000
Content-Length:508208
Content-Type:image/png
Date:Thu, 16 Feb 2017 18:25:05 GMT
Last-Modified:Wed, 15 Feb 2017 19:09:44 GMT
Server:AmazonS3
Vary:Origin, Access-Control-Request-Headers, Access-Control-Request-Method 

现在,如果crossOrigin='anonymous'并且图片不是来自缓存,则此功能正常。如果未设置crossOrigin属性,我会:

Accept-Ranges:bytes
Cache-Control:max-age=2592000
Content-Length:508208
Content-Type:image/png
Date:Thu, 16 Feb 2017 19:03:53 GMT
Last-Modified:Wed, 15 Feb 2017 19:09:44 GMT
Server:AmazonS3

或者它在控制台上抛出CORS错误而没有在响应头上显示任何元数据。我尝试在url(?somethingsomething)的末尾添加一个随机字符串,以便永远不会从缓存中抓取它们,这完全解决了问题。但这只是一个黑客,它现在可以工作,但它绝对不是我想要的解决方案。我认为Chrome正在对缓存做一些事情,我很难跟踪问题的根源,除了在我的机器上很难重现这个问题的事实,因为它总是从缓存中检索截图,即使我完全使用新图像和禁用/清除缓存。这很令人困惑。

3 个答案:

答案 0 :(得分:3)

  

查看编辑,我确实尝试将crossOrigin属性设置为no   运气好,我将useCORS设置为true(忘了对不起)。   还是没有运气。

我修复了谷歌浏览器,AWS S3和多个来源的结合所带来的一些问题。

我发现了这个stackoverflow线程: Chrome + CORS + cache - requesting same file from two different origins

此错误报告的链接: https://bugs.chromium.org/p/chromium/issues/detail?id=260239

无论如何,您都可以尝试使用html2canvas的此修改版: https://gist.github.com/CrandellWS/6bc2078aced496004d7a045e6360f19b

使用选项:

allowTaint : false,
useCORS: true

希望有帮助。

仅供参考,这会将当前时间戳添加到cors图片网址,从而避免了我在Chrome上遇到的缓存问题... https://gist.github.com/CrandellWS/6bc2078aced496004d7a045e6360f19b#file-html2canvas-js-L6838

这意味着它将通过重新下载这些图像来影响性能...

原始帖子: https://github.com/niklasvh/html2canvas/issues/1544#issuecomment-435640901

答案 1 :(得分:1)

我通过在IMG标签上添加crossOrigin属性解决了该错误。因此,您的代码将如下所示(在React js处标记):

<Image crossOrigin="true" />

我在带有CORS的S3存储桶中的配置:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>http://localhost:8000</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
<CORSRule>
    <AllowedOrigin>https://testing.d1wr8lk28mi6l0.amplifyapp.com</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
</CORSConfiguration>

HTML2CANVAS:

 html2canvas(getWrapper, { allowTaint: true, useCORS: true, logging: true })
  .then((canvas) => {
    const imgData = canvas.toDataURL('image/png');
    console.log(imgData);
  });

答案 2 :(得分:0)

我通过在 html2canvas 中添加 proxy:( image src ) 选项解决了这个问题。现在您的图片也包含在 pdf 中

打字稿代码:

download() {
        var data = document.getElementById('view-eob');
        html2canvas(data, { proxy: this.eobDetail.member.parentCompany.logo })
        .then(canvas => {
            var imgWidth = 208;
            var imgHeight = canvas.height * imgWidth / canvas.width;
            const contentDataURL = canvas.toDataURL('image/png')
            let pdf = new jsPDF('p', 'mm', 'a4');
            var position = 0;
            pdf.addImage(contentDataURL, 'PNG', 0, position, imgWidth, imgHeight)
            pdf.save(`${this.eobDetail.episode.name}-EOB.pdf`);
        });
    }

HTML 代码:

<div>
     <img [src]="this.eobDetail.member.parentCompany.logo"/>
</div>
<button type="button" (click)="download()"> Download</button>