Html <img src=...> works but JS Image loading cause CORS error
Asked Answered
D

3

33

I want to create picture editor in js+jquery. At the first step i ask user to give image url. But I come across problem when i try load image data inside JS (to generate base64 image uri). I get error in console: … has beeb blocked by CORS policy: Access-Control-Allow-Origin …. But I wonder why? If in html file i create for instance (image hotlink):

<img  src="https://static.pexels.com/photos/87293/pexels-photo-87293.jpeg" />

The browser load image without any CORS problems ! Here is my JS code which for the same image throw CORS problem:

 function downloadFile(url) {
    console.log({url});    
    var img = new Image();
    img.onload = function() {
        console.log('ok'); 
        // never execute because cors error
        // … make base64 uri with image data needed for further processing
    };

    img.crossOrigin = "Anonymous";
    img.src = url;
}

So the question is - how to force JS to load image (as html-tag load it) and convert it to base64 url avoiding CORS problem?

https://static.pexels.com/photos/87293/pexels-photo-87293.jpeg

Dorolisa answered 24/3, 2017 at 13:22 Comment(6)
What web server are you testing on?Diatomaceous
I not use any web server - i crate fat client application: only JS+HTML+CSSTorbart
There's your problem. You can't just run the file from your file system. Take a look into testing/developing on LAMP/XAMPP or a NodeJS lightweight server such as http-serverDiatomaceous
No - i user node.js as my web serwer. I miss understan your question - ofcourse i put my JS+HTML+CSS files into file server.Torbart
Maybe this will help, then: #18310894Diatomaceous
@J.Titus — Since the image URL is one provided by the user, and is (presumably) third party hosted, that seems unlikely.Ardoin
D
22

I try to found solution my self (JS ES6) but find only-partially. We are able to load img from no-CORS support src into canvas but browser switch cavnas into 'taint mode' which not allow us to call toDataURL (and any other access to content).

function loadImgAsBase64(url, callback) {
  let canvas = document.createElement('CANVAS');
  let img = document.createElement('img');
  //img.setAttribute('crossorigin', 'anonymous');
  img.src = url;

  img.onload = () => {
    canvas.height = img.height;
    canvas.width = img.width;
    let context = canvas.getContext('2d');
    context.drawImage(img, 0, 0);
    let dataURL = canvas.toDataURL('image/png');
    canvas = null;
    callback(dataURL);
  };
}


let url = 'http://lorempixel.com/500/150/sports/9/';

this.loadImgAsBase64(url, (dataURL) => {
   msg.innerText = dataURL.slice(0,50)+'...';
});
IMAGE DATA: loading...<br>
<div id="msg"></div>

So only way to overcome this obstacle is to create proxy server (e.g. in PHP) which will have CORS 'on' and it will download images for given url and send back to our app in JS. I found some free server https://cors-anywhere.herokuapp.com which we can use to in development to tests. Below there is full functional code which return dataUri from given image url:

function loadImgAsBase64(url, callback) {
  let canvas = document.createElement('CANVAS');
  let img = document.createElement('img');
  img.setAttribute('crossorigin', 'anonymous');
  img.src = 'https://cors-anywhere.herokuapp.com/' + url;

  img.onload = () => {
    canvas.height = img.height;
    canvas.width = img.width;
    let context = canvas.getContext('2d');
    context.drawImage(img, 0, 0);
    let dataURL = canvas.toDataURL('image/png');
    canvas = null;
    callback(dataURL);
  };
}


let url = 'http://lorempixel.com/500/150/sports/9/';

this.loadImgAsBase64(url, (dataURL) => {
   msg.innerText = dataURL.slice(0,50)+'...';
   // show pic
   document.body.innerHTML += `<img src="${dataURL}">`
});
IMAGE DATA Loading...<br>
<div id="msg"></div>

Thats all :) (I tested it on chrome, firefox and safari)

Dorolisa answered 24/3, 2017 at 13:45 Comment(5)
Do note that hosting such a proxy server will make your server vulnerable to server-side request forgery (SSRF) attacks.Raina
@Raina can you explain more how such attacks will works - in case when our proxy will setup CORS to allow requests only from our JS-app domain?Torbart
Let's say your web server also has an admin interface at /admin which is only available for localhost. Let's say this admin interface can show current usage stats in image form at /admin/stats?format=png. I now start your picture editor and enter http://localhost/admin/stats?format=png as the image url. Your PHP proxy happily fetches that file for me, and the request succeeds, because it originates from the web server itself.Raina
@Raina I don't know that I fully understand you. I want to allow my users to fetch any image and edit it. So they go to https://myeditor.com, they put link of their image and can edit it (because https://myeditor.com use https://myproxy.com with allowed CORS to read the image "in edit mode") . I don get where is the problem with this behaviour? Any other third-party site like https://evil.com cannot use my proxy to fetch images... - only users who use https://myeditor.com can use my proxy... where is the problem? :)Torbart
A user can make your proxy fetch any image they want (by putting the link in your editor). The request will originate from your proxy, use your proxy's IP address and your proxy's network permissions. This is not a problem in itself, but becomes a problem if your proxy has access to anything that the world should not have access to.Raina
B
0

I had a similar issue and my issue was solved when I passed query parameter as part of the image url.

sample: http://example.com/image.jpeg?test=123

Bovid answered 17/10, 2021 at 16:10 Comment(1)
For me also solved issue in one environment after deploying same code in another environment it's getting same errorManama
T
-5

The only way to avoid CORS is to make changes to avoid cross-origin sharing, at least let the browser thinks that it is cross-origin.

Or, you have to modify the server to support CORS.

Twelve answered 4/2, 2019 at 5:54 Comment(1)
"make changes to avoid cross-origin sharing" - how to do it? Provide example codeTorbart

© 2022 - 2024 — McMap. All rights reserved.