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

Posted

技术标签:

【中文标题】如何使用 html2Canvas 和 AWS S3 图像处理 CORS?【英文标题】:How do I handle CORS with html2Canvas and AWS S3 images? 【发布时间】:2017-07-04 22:20:45 【问题描述】:

我知道以前有人问过类似的问题,但我仍然无法解决。我有一个div,其中的图像是从 AWS s3 的存储桶中加载的,它们加载完全没问题。

现在我希望能够将特定 div 中的任何内容保存为 jpeg(比如截屏),插件 html2canvas 可以帮助解决这个问题。问题是,当我尝试实际保存它(或简单地立即显示此类屏幕截图的结果)时,我遇到了这些问题:

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

CORS 政策已阻止访问图像

为了解决这个问题,我在我的 AWS S3 存储桶上设置了 CORS,但这似乎不起作用(或部分起作用)。我注意到,当插件使用它们生成 jpeg 时,这些图像的响应标头没有 CORS 元数据。然后我尝试在div 内的这些图像中设置crossOrigin="anonymous",但它会立即引发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,并且图像 url 是从服务器检索的。这意味着,一旦我得到这个 url 数组,我就会生成:

<div>
   urls.map(url => <img src=url  />) 
</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) 的末尾添加一个随机字符串,这样它们就永远不会从缓存中被抓取,这完全解决了这个问题。但这只是一个 hack,它现在可以工作,但它绝对不是我正在寻找的解决方案。我认为 Chrome 正在对缓存做一些事情,我很难跟踪问题的根源,除了在我的机器上很难重现这个问题,因为即使我完全使用它,它总是从缓存中检索屏幕截图新图像和禁用/清除缓存。这很混乱。

【问题讨论】:

Access to image has been blocked by CORS policy - 显示您用于获取图像的代码 您必须直接在文档中加载带有crossOrigin 属性设置为'anonymous' 的图像,或者您可以尝试useCORS h2c 选项。 allowTaint 选项只是说你不在乎它是否会污染画布。 查看编辑,我确实尝试设置 crossOrigin 属性,但没有成功,我使用 useCORS 设置为 true(忘了说抱歉)。还是没有运气。 啊,你的存储桶设置有问题。已经有一段时间了,但你的 conf 对我来说似乎没问题,也许删除 Allowed header 字段,我认为没有必要。可以查this answer,挺老的,我也没有s3账号可以测试了…… 您能否捕获并显示失败请求的完整请求和响应标头以及整个 CORS 错误? 【参考方案1】:

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

我修复了我在结合使用 Google Chrome、AWS S3 和多个来源时遇到的一些 cors 问题。

我发现了这个 *** 线程: 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 图像 url 以回避我在 Chrome 上遇到的缓存问题... https://gist.github.com/CrandellWS/6bc2078aced496004d7a045e6360f19b#file-html2canvas-js-L6838

这意味着重新下载这些图像会影响性能...

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

【讨论】:

我看到您添加到 html2canvas 的编辑。它有助于避免在渲染后显示空白图像。我可以看到您在 img 的 src 末尾添加了 date.getTime() 作为随机数!你能解释一下为什么吗?这是否与缓存问题有关? @Wowali 对我来说主要是针对 AWS Bucket 的一种不使用缓存版本并将其设置为 anonymous 的方式,这是 cors 工作所需要的......以防止污染......跨度> 我在github.com/niklasvh/html2canvas/issues/…github.com/niklasvh/html2canvas/issues/…项目的githubs问题列表上发布了这个 是的,它帮助我解决了一个域名的 CORS 问题……非常感谢 html2pdf 有固定的 cors 版本吗?或任何更新的解决方案请...谢谢【参考方案2】:

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

<Image crossOrigin="true" />

以及我在 S3 存储桶中的 CORS 配置:

<?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);
  );

【讨论】:

【参考方案3】:

我通过在 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>

【讨论】:

如果是多张图片怎么办?

以上是关于如何使用 html2Canvas 和 AWS S3 图像处理 CORS?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 S3 用作静态网页和 EC2 作为 REST API 一起使用? (AWS)

如何使用 AWS 在 Docker Cloud 中设置链接到 S3 的卷?

如何使用 AWS AppSync 将文件上传到 AWS S3

我如何通过AWS SNS设置有关上传事件的AWS S3?

如何使用 Rails 和 Active Storage 实现 AWS S3 分段上传?

通过 jclouds 使用 AWS (S3) - 如何承担角色