fetch base64 string failed on Safari

Created on 28 Feb 2017  Â·  5Comments  Â·  Source: github/fetch

here is my code, work well on Chrome56:

function dataURItoFile(dataURI, filename) {
  const mimeType = dataURI.split(',')[0].split(':')[1].split(';')[0]
  return fetch(dataURI)
    .then(res => res.arrayBuffer())
    .then(buf => new File([buf], filename, { type: mimeType }))
}

dataURI: base64 string

but on Safari10:

XMLHttpRequest cannot load data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABaAAAAQACAYAAAAXy/6SAAAAAXNSR0IArs4c6QAAQABJREFUeAHsXQlAVcUa/tgXUQRBRVLQm6KIIhpaUmkmUoqllWgmlgaZTzKXXF+Z+so1rQif+iA3zFwqNckyjFzCXFJEFEXFVERQUARRdnjfnLtw2ZQ2QJ1fuWfOnDlzZr5zzpyZb/75f4O2bT1KIEUiIBGQCEgEqkTg1KmYKo/dzwf4fbifqyfrJhGQCEgEJAISAYmAREAiIBGQCEgEJAISAYlADSBgWAPXkJeQCEgEJAISAYmAREAiIBGQCEgEJAISAYmAREAiIBGQCEgEJAISgQcQAUlAP4A3XVZZIiARkAhIBCQCEgGJgERAIiARkAhIBCQCEgGJgERAIiARkAjUBAKSgK4JlOU1JAISAYmAREAiIBGQCEgEJAISAYmAREAiIBGQCEgEJAISAYnAA4iAJKAfwJsuqywRkAhIBCQCEgGJgERAIiARkAhIBCQCEgGJgERAIiARkAhIBGoCAUlA1wTK8hoSAYmAREAiIBGQCEgEJAISAYmAREAiIBGQCEgEJAISAYmAROABREAS0A/gTZdVlghIBCQCEgGJgERAIiARkAhIBCQCEgGJgERAIiARkAhIBCQCNYGAJKBrAmV5DYmAREAiIBGQCEgEJAISAYmAREAiIBGQCEgEJAISAYmAREAi8AAiIAnoB/CmyypLBCQCEgGJgERAIiARkAhIBCQCEgGJgERAIiARkAhIBCQCEoGaQMC4Ji4ir/FgI2DYsBGMW7WDkaqtsjVu1RYGVg1QfPUyiq4ko+jS78g/8DMKz54ASkoebLBk7SUCEgGJgERAIiARkAhIBCQCEgGJgERAIiARkAhIBCQC9xECBm3bekjG7z66oXWpKkaOzrAcOgamjz1drWIV/p6A7MXTUJR8vlrpZSKJQE0hcOpUTE1dqk5dh9+HOlUeWRiJgERAIiARkAhIBCQCEgGJgERAIiARkAhIBO49BKQG9L13z+p+iY2MYPHCSFj6BQJG1X/Eis6dQtHli3W/frKEEgGJgERAIiARkAhIBCQCEgGJgERAIiARkAhIBCQCEgGJQLUQqD47WK3sZKIHHQEDE1NYTVoI00ee+ENQ5O3cguylH9AER/EfOk8mlghIBCQCEgGJgERAIiARkAhIBCQCEgGJgERAIiARkAhIBOouAtIJYd29N/dkyeqNmVG3yWf3HujvZVMtbO1UTlDxz65aqUsTefX3gXvprgxJBCQCEgGJgERAIiARkAhIBCQCEgGJgERAIiARkAhIBB5YBKQG9AN76//+ipv7vASzJ/v+oYzzdm6m5vOHf1Lz2RNhUYvQ5vZZ/LJvF37+bhsiYzOquL4rpi99Dy/3dIExCvF65BpMHBuCxCpSQxWIbyNGQ1DVx8NGYdCiQ7qUXsMnYFzAS3CzuYz3O7yEjbojDNgNxtwFU2C/4D9IifkGgUPnVX0N/fNkWCIgEZAISAQkAhIBiYBEQCIgEZAISAQkAn8RgTYqR7w1sj+6d3WFpYXZX8ytbp5eWFiEmLhELFu9Hft+O1k3CylLJRGQCJRBQBLQZeCQO38WAUO7prB8dfwfOl1tduPPks9AYNgH8HKw4jU....

so, is that a bug?

Most helpful comment

The problem

It boils down to this code:

url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
xhr = new XMLHttpRequest
xhr.open('GET', url)
xhr.send()

skarmavbild 2017-03-25 kl 21 18 16

When sortering the url i saw the full error message:

XMLHttpRequest cannot load < URL >. Cross origin requests are only supported for HTTP.

I tested the same code in Safari TP and it worked just fine. So did the native fetch version of your code also.

Workaround

Use any other way to make a File out of a base64. Make your pick: http://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript

Code review

using blob instead of arraybuffer yields a better result, you don't have to get the mimeType from the base64 since it will be included when you return the blob. Beside blob may also be a better choice for you since you can't construct files on all browsers (see note 2 on caniuse.com)

  return fetch(dataURI)
    .then(res => res.blob())
    .then(blob => new File([blob], filename, { type: blob.type }))

What can the polyfill do to fix it?

Parse the url, see if it's a data URI and if it's convert the data URI to a blob internally without using xhr

All 5 comments

The problem

It boils down to this code:

url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
xhr = new XMLHttpRequest
xhr.open('GET', url)
xhr.send()

skarmavbild 2017-03-25 kl 21 18 16

When sortering the url i saw the full error message:

XMLHttpRequest cannot load < URL >. Cross origin requests are only supported for HTTP.

I tested the same code in Safari TP and it worked just fine. So did the native fetch version of your code also.

Workaround

Use any other way to make a File out of a base64. Make your pick: http://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript

Code review

using blob instead of arraybuffer yields a better result, you don't have to get the mimeType from the base64 since it will be included when you return the blob. Beside blob may also be a better choice for you since you can't construct files on all browsers (see note 2 on caniuse.com)

  return fetch(dataURI)
    .then(res => res.blob())
    .then(blob => new File([blob], filename, { type: blob.type }))

What can the polyfill do to fix it?

Parse the url, see if it's a data URI and if it's convert the data URI to a blob internally without using xhr

Thank you!

@jimmywarting Thanks for your extensive research. Do you think this is something we should aim to fix in our polyfill? If not, I'm keen on closing this out.

I'm on the fence.
It would be nice if it worked but I also thing its a bad practise to have a base64 URL to begin with.
Think you should always aim to have a arrays buffers or blob. Decoding and encoding is only a unnecessary overhead and there are better ways to handle it IMAO

I would agree on a workaround if it was easy (e.g. 2–3 lines of code). However, since the logic to convert a base64 would inflate the size of this polyfill, I don't think this is something that we should be working around of, and instead it should be the responsibility of the user to avoid using fetch() for this on unsupporting browsers.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

indranildutta06 picture indranildutta06  Â·  3Comments

poppinlp picture poppinlp  Â·  4Comments

kocur4d picture kocur4d  Â·  3Comments

huanghaiyang picture huanghaiyang  Â·  3Comments

proofrock picture proofrock  Â·  3Comments