canvas使用跨域的图片时,image.crossOrigin = 'Anonymous',Tainted canvases may not be exported?

canvas使用跨域的图片时,不加 image.crossOrigin = 'Anonymous'; 图片可以绘制,但是不能调用 toBlob(), toDataURL() 或 getImageData() 方法,调用它们会抛出安全错误。

Unable to get data URL. Failed to execute ‘toDataURL’ on ‘HTMLCanvasElement’: Tainted canvases may not be exported.

如果加上 image.crossOrigin = 'Anonymous'; 报错 Access to image at 'http://10.10.10.112/product/AVWT-154FESSA.png' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.


问题的原因:是后端没有配置允许接受跨域

阅读 1.4k
avatarAI BotBETA

这个问题是由于浏览器的同源策略造成的。在加载跨域图片时,浏览器会阻止对图片的某些操作,以避免潜在的安全问题。

首先,让我们解释一下同源策略。同源策略是一种安全协议,它规定了在没有明确权限的情况下,一个Web应用(源)不能与另一个源共享资源。这是为了防止恶意脚本在未经用户许可的情况下对用户的源进行操作。在浏览器的上下文中,"同源"指的是协议、域名和端口都相同。

在你的情况下,你试图在canvas中绘制一个来自不同源的图片(跨域)。如果不设置image.crossOrigin属性,浏览器会阻止对图片的某些操作,因为这可能会暴露敏感信息。因此,当你尝试调用toBlob(), toDataURL(), 或 getImageData() 方法时,会抛出一个安全错误。

然而,当你设置image.crossOrigin = 'Anonymous'时,你实际上是告诉浏览器允许对这个跨域图片进行操作。但这里的问题是,你的后端服务器没有正确配置CORS(跨源资源共享)策略。

你提到Access-Control-Allow-Origin: *已经添加到后端接口,但你仍然收到一个错误消息。这可能是由于服务器没有正确地响应跨域请求的预检请求。在CORS协议中,浏览器会首先发送一个预检请求(OPTIONS请求),以确定服务器是否允许跨域请求。服务器需要正确地响应这个预检请求,包括添加适当的CORS头部。

为了解决这个问题,你需要确保服务器正确地配置了CORS策略。具体的步骤可能因服务器的类型和配置而异,但通常你需要添加以下头部:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS

此外,如果你的服务器使用的是Express.js,你可能会使用cors中间件来简化CORS配置:

var express = require('express');
var cors = require('cors');
var app = express();

app.use(cors());

以上只是对这个问题的一种可能的解决方案。实际的解决方案可能会根据你的具体情况有所不同。

1 个回答

换下小写试试

image.setAttribute(‘crossorgin’,’anonymous’)

将image作为文件读取blob流,ctx.toBlob 试试

export function imageToFileByCanvas(image: HTMLImageElement, fileName: string = "image.jpg"): Promise<File> {
    const canvas = document.createElement("canvas")
    canvas.width = image.width
    canvas.height = image.height

    const ctx = canvas.getContext("2d")!
    ctx.drawImage(image, 0, 0)

    return new Promise(resolve => canvas.toBlob(blob => resolve(new File([blob!], fileName))))
}

async function getImage(){
      const file = await imageToFileByCanvas(image, "image.jpg")
    const imgUrl = URL.createObjectURL(file) // image 内存地址
}

export function imageToFileByBlob(image: HTMLImageElement, fileName: string = "image.jpg") {
    const binStr = atob(image.src.split(",")[1])
    const len = binStr.length
    const arr = new Uint8Array(len)
    for (let i = 0; i < len; i++) {
        arr[i] = binStr.charCodeAt(i)
    }

    const blob = new Blob([arr], { type: "image/png" })
    return new File([blob], fileName)
}

stackoverflow

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题