Javascript 为什么 canvas.toDataURL() 会抛出安全异常?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2390232/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 00:05:42  来源:igfitidea点击:

Why does canvas.toDataURL() throw a security exception?

javascripthtmlcanvascross-domain

提问by pop850

Did I not get enough sleep or what? This following code

是我睡眠不足还是怎么的?下面这段代码

var frame=document.getElementById("viewer");
frame.width=100;
frame.height=100;

var ctx=frame.getContext("2d");
var img=new Image();
img.src="http://www.ansearch.com/images/interface/item/small/image.png"

img.onload=function() {
    // draw image
    ctx.drawImage(img, 0, 0)

    // Here's where the error happens:
    window.open(frame.toDataURL("image/png"));
}

is throwing this error:

正在抛出这个错误:

SECURITY_ERR: DOM Exception 18

There's no way this shouldn't work! Can anyone explain this, please?

这绝不可能行不通!任何人都可以解释一下吗?

采纳答案by Bob

In the specsit says:

规格中它说:

Whenever the toDataURL() method of a canvas element whose origin-clean flag is set to false is called, the method must raise a SECURITY_ERR exception.

每当调用其 origin-clean 标志设置为 false 的画布元素的 toDataURL() 方法时,该方法必须引发 SECURITY_ERR 异常。

If the image is coming from another server I don't think you can use toDataURL()

如果图像来自另一台服务器,我认为您不能使用 toDataURL()

回答by Philip Nuzhnyy

Setting cross origin attribute on the image objects worked for me (i was using fabricjs)

在对我有用的图像对象上设置交叉原点属性(我使用的是fabricjs)

    var c = document.createElement("img");
    c.onload=function(){
        // add the image to canvas or whatnot
        c=c.onload=null
    };
    c.setAttribute('crossOrigin','anonymous');
    c.src='http://google.com/cat.png';

For those using fabricjs, here's how to patch Image.fromUrl

对于那些使用 fabricjs 的人,这里是如何修补 Image.fromUrl

// patch fabric for cross domain image jazz
fabric.Image.fromURL=function(d,f,e){
    var c=fabric.document.createElement("img");
    c.onload=function(){
        if(f){f(new fabric.Image(c,e))}
        c=c.onload=null
    };
    c.setAttribute('crossOrigin','anonymous');
    c.src=d;
};

回答by James Foster

If the image is hosted on a host that sets either of Access-Control-Allow-Origin or Access-Control-Allow-Credentials, you can use Cross Origin Resource Sharing (CORS). See here (the crossorigin attribute) for more details.

如果图像托管在设置了 Access-Control-Allow-Origin 或 Access-Control-Allow-Credentials 的主机上,您可以使用跨源资源共享 (CORS)。有关更多详细信息,请参见此处(crossorigin 属性)。

Your other option is for your server to have an endpoint that fetches and serves an image. (eg. http://your_host/endpoint?url=URL) The downside of that approach being latency and theoretically unnecessary fetching.

您的另一个选择是让您的服务器拥有一个端点来获取和提供图像。(例如http://your_host/endpoint?url=URL)这种方法的缺点是延迟和理论上不必要的获取。

If there are more alternate solutions, I'd be interested in hearing about them.

如果有更多替代解决方案,我有兴趣了解它们。

回答by DitherSky

Seems there is a way to prevent that if image hosting able to provide the following HTTP headers for the image resources and browser supports CORS:

如果图像托管能够为图像资源提供以下 HTTP 标头并且浏览器支持 CORS,则似乎有一种方法可以防止这种情况:

access-control-allow-origin: *
access-control-allow-credentials: true

It is stated here: http://www.w3.org/TR/cors/#use-cases

此处说明:http: //www.w3.org/TR/cors/#use-cases

回答by jose920405

Finally i found the solution. Just need add the crossOriginas third param in fromURLfunc

最后我找到了解决方案。只需要crossOriginfromURLfunc 中添加第三个参数

fabric.Image.fromURL(imageUrl, function (image) {
            //your logic
    }, { crossOrigin: "Anonymous" });

回答by Qwerty

I was able to make it work using this:

我能够使用这个让它工作:

Write this on first line of your .htaccesson your source server

将此写在.htaccess源服务器上的第一行

Header add Access-Control-Allow-Origin "*"

Then when creating an <img>element, do it as follows:

然后在创建<img>元素时,按如下方式进行:

// jQuery
var img = $('<img src="http://your_server/img.png" crossOrigin="anonymous">')[0]

// or pure
var img = document.createElement('img');
img.src='http://your_server/img.png';
img.setAttribute('crossOrigin','anonymous');

回答by CarinaPilar

I had the same problem and all the images are hosted in the same domain... So, if someone is having the same problem, here is how I solved:

我遇到了同样的问题,所有图像都托管在同一个域中......所以,如果有人遇到同样的问题,我是这样解决的:

I had two buttons: one to generate the canvas and another one to generate the image from the canvas. It only worked for me, and sorry that I don't know why, when I wrote all the code on the first button. So when I click it generate the canvas and the image at the same time...

我有两个按钮:一个用于生成画布,另一个用于从画布生成图像。它只对我有用,很抱歉,当我在第一个按钮上编写所有代码时,我不知道为什么。所以当我点击它时同时生成画布和图像......

I always have this security problem when the codes were on different functions... =/

当代码在不同的功能上时,我总是遇到这个安全问题...... =/

回答by Mike Robinson

You can't put spaces in your ID

您不能在 ID 中输入空格

Update

更新

My guess is that image is on a different server than where you're executing the script. I was able to duplicate your error when running it on my own page, but it worked fine the moment I used an image hosted on the same domain. So it's security related - put the image on your site. Anyone know why this is the case?

我的猜测是该图像与您执行脚本的服务器位于不同的服务器上。在我自己的页面上运行它时,我能够复制您的错误,但是当我使用托管在同一域上的图像时,它运行良好。所以它与安全相关 - 将图像放在您的网站上。有谁知道为什么会这样?

回答by JonathanC

If you are simply drawing some images on a canvas, make sure you are loading the images from the same domain.

如果您只是在画布上绘制一些图像,请确保加载来自同一域的图像。

www.example.comis different to example.com

www.example.comexample.com不同

So make sure your images and the url you have in your address bar are the same, www or not.

因此,请确保您的图片和地址栏中的 url 相同,无论是否为 www。

回答by horstwilhelm

I'm using fabric.js and could resolve this by using toDatalessJSON instead of toDataURL:

我正在使用 fabric.js 并且可以通过使用 toDatalessJSON 而不是 toDataURL 来解决这个问题:

canvas.toDatalessJSON({ format: 'jpeg' }).objects[0].src

Edit: Nevermind. This results in just the background image being exported to JPG, without the drawing on top so it was not entirely useful after all.

编辑:没关系。这导致仅将背景图像导出为 JPG,而没有在顶部绘制,因此它毕竟不是完全有用的。