canvas.toDataURL () SecurityError


76

Vì vậy, tôi đang sử dụng bản đồ google và tôi nhận được hình ảnh giống như thế này

<img id="staticMap"
        src="http://maps.googleapis.com/maps/api/staticmap?center=Brooklyn+Bridge,New+York,NY&zoom=13&size=600x300&maptype=roadmap
&markers=color:blue%7Clabel:S%7C40.702147,-74.015794&markers=color:green%7Clabel:G%7C40.711614,-74.012318
&markers=color:red%7Ccolor:red%7Clabel:C%7C40.718217,-73.998284&sensor=false">

Tôi cần phải lưu nó. Tôi đã tìm thấy điều này:

function getBase64FromImageUrl(URL) {
    var img = new Image();
    img.src = URL;
    img.onload = function() {

        var canvas = document.createElement("canvas");
        canvas.width = this.width;
        canvas.height = this.height;

        var ctx = canvas.getContext("2d");
        ctx.drawImage(this, 0, 0);

        var dataURL = canvas.toDataURL("image/png");

        alert(dataURL.replace(/^data:image\/(png|jpg);base64,/, ""));

    };
}

Nhưng tôi gặp vấn đề này:

Uncaught SecurityError: Không thực thi được 'toDataURL' trên 'HTMLCanvasElement': có thể không xuất được các tấm vải bị nhiễm bẩn.

Tôi đã tìm kiếm các bản sửa lỗi. Tôi đã tìm thấy một mẫu ở đây Cách sử dụng CORS nhưng tôi vẫn không thể buộc 2 đoạn mã này lại với nhau để làm cho nó hoạt động. Có lẽ tôi đang làm sai cách và có một cách đơn giản hơn để làm điều đó? Tôi đang cố gắng lưu ảnh này để có thể chuyển dữ liệu đến máy chủ của mình. Vì vậy, có thể ai đó đã làm điều gì đó như thế này và biết cách làm .toDataURL()việc như tôi cần?

Câu trả lời:


100

Trừ khi google cung cấp hình ảnh này với Access-Control-Allow-Origintiêu đề chính xác , khi đó bạn sẽ không thể sử dụng hình ảnh của họ trong canvas. Điều này là do không có sự CORSchấp thuận. Bạn có thể đọc thêm về điều này ở đây , nhưng về cơ bản nó có nghĩa là:

Mặc dù bạn có thể sử dụng hình ảnh mà không có sự chấp thuận của CORS trong canvas của mình, nhưng làm như vậy sẽ có lợi cho canvas. Khi canvas đã bị ố, bạn không thể lấy lại dữ liệu ra khỏi canvas được nữa. Ví dụ: bạn không thể sử dụng các phương thức canvas toBlob (), toDataURL () hoặc getImageData (); làm như vậy sẽ tạo ra một lỗi bảo mật.

Điều này bảo vệ người dùng khỏi bị lộ dữ liệu riêng tư bằng cách sử dụng hình ảnh để lấy thông tin từ các trang web từ xa mà không được phép.

Tôi khuyên bạn chỉ nên chuyển URL sang ngôn ngữ phía máy chủ của bạn và sử dụng curl để tải xuống hình ảnh. Hãy cẩn thận để vệ sinh cái này mặc dù!

BIÊN TẬP:

Vì câu trả lời này vẫn là câu trả lời được chấp nhận, bạn nên xem câu trả lời của @ shadyshrif , sẽ sử dụng:

var img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;

Điều này sẽ chỉ hoạt động nếu bạn có quyền chính xác, nhưng ít nhất sẽ cho phép bạn làm những gì bạn muốn.


1
Tôi sẽ tiếp tục đề xuất thay thế từ xa từ @Prisoner và đề xuất đặt nó thành hành vi mặc định. Máy chủ gần như chắc chắn sẽ có thể nhận img.src sau đó gửi * / * cURL hình ảnh nhanh hơn so với việc máy khách có thể mã hóa hình ảnh có nguồn gốc cục bộ và ĐĂNG nó lên máy chủ. Có lẽ, chỉ khi xác thực phía máy khách được yêu cầu (tức là nỗ lực của máy chủ của bạn kết thúc bằng a 403), bạn có thể quay lại sử dụng canvas.toDataURL(img)với hy vọng rằng nó được cung cấp từ cùng một nguồn gốc như trang. Hành vi mặc định này cũng sẽ dẫn đến tập tin gốc (EXIF et al.)
Alastair

4
Tôi đã đặt nhóm Google Cloud Storage của mình thành "Access-Control-Allow-Origin: *" nhưng tôi vẫn gặp lỗi bảo mật này khi cố gắng sử dụng phương thức toDataURL (). Hình ảnh đang được cung cấp cho Canvas thông qua URL được tạo từ "getImageServingUrl"
Mr Pablo

1
Có giải pháp nào chưa? Câu trả lời này thổi.
Yeats

Tuyệt quá ! Cảm ơn rất nhiều cho câu trả lời này!
Kevin Vincent

4
TIL: Điều quan trọng là phải đặt crossOriginthuộc tính trước khi thiết lập img.src.
horstwilhelm

56

Chỉ cần sử dụng crossOriginthuộc tính và chuyển 'anonymous'làm tham số thứ hai

var img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;

6
Để làm rõ, điều này sẽ không hoạt động đối với các máy chủ trực tiếp không cho phép bạn cung cấp tài nguyên. Điều đó có nghĩa là điều này sẽ chỉ hoạt động đối với các tài nguyên công cộng hoặc các máy chủ được định cấu hình sai.
m3nda

3
Tôi cũng phải thêm dấu thời gian vào URL hình ảnh để tránh máy chủ lưu trữ phản hồi với 304 mà không có tiêu đề Access-Control-Allow-Origin. Như thế nàyimg.src = url + '?' + new Date().getTime();
Kirby

không làm việc cho tôi trong IE11 với hình ảnh nguồn sử dụng dữ liệu url
AlexM

4

Phương pháp này sẽ ngăn bạn gặp lỗi 'Access-Control-Allow-Origin' từ máy chủ mà bạn đang truy cập.

var img = new Image();
var timestamp = new Date().getTime();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url + '?' + timestamp;

3

Hãy thử mã bên dưới ...

<img crossOrigin="anonymous"
     id="imgpicture" 
     fall-back="images/penang realty,Apartment,house,condominium,terrace house,semi d,detached,
                bungalow,high end luxury properties,landed properties,gated guarded house.png" 
     ng-src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" 
     height="220"
     width="200"
     class="watermark">

2
lý do giá trị vô nghĩa của fall-backthuộc tính là gì?
y.bregey

0

Trong trường hợp của tôi, tôi đang sử dụng điều khiển WebBrowser (buộc IE 11) và tôi không thể vượt qua lỗi. Việc chuyển sang CefSharp sử dụng Chrome đã giải quyết được vấn đề đó cho tôi.


0

Tôi đã có cùng một thông báo lỗi. Tôi có tệp ở dạng .html đơn giản, khi tôi chuyển tệp sang php trong Apache, nó hoạt động

html2canvas(document.querySelector('#toPrint')).then(canvas => {
            let pdf = new jsPDF('p', 'mm', 'a4');
            pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 0, 0, 211, 298);
            pdf.save(filename);
        });

-3

Bằng cách sử dụng vải js, chúng tôi có thể giải quyết vấn đề lỗi bảo mật này trong IE.

    function getBase64FromImageUrl(URL) {
        var canvas  = new fabric.Canvas('c');
        var img = new Image();
        img.onload = function() {
            var canvas1 = document.createElement("canvas");
            canvas1.width = this.width;
            canvas1.height = this.height;
            var ctx = canvas.getContext('2d');
            ctx.drawImage(this, 0, 0);
            var dataURL = canvas.toDataURL({format: "png"});
        };
        img.src = URL;
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.