Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a file or blob from an object URL?

People also ask

How do I get Blob link URL?

Right-click on the webpage and click “Inspect” in the menu. When the DevTools panel opens, click on the three vertical dots in the top-right corner and select “Undock into a separate window.” Press Ctrl + F on Windows or Cmd + F on Mac devices to find the blob URL. Enter “ blob:HTTP ” to find the link for the video.

What is Blob HTTP URL?

Blob URL/Object URL is a pseudo protocol to allow Blob and File objects to be used as URL source for things like images, download links for binary data and so forth. For example, you can not hand an Image object raw byte-data as it would not know what to do with it.

What is URL createObjectURL ()?

createObjectURL() The URL. createObjectURL() static method creates a string containing a URL representing the object given in the parameter. The URL lifetime is tied to the document in the window on which it was created. The new object URL represents the specified File object or Blob object.


Modern solution:

let blob = await fetch(url).then(r => r.blob());

The url can be an object url or a normal url.


As gengkev alludes to in his comment above, it looks like the best/only way to do this is with an async xhr2 call:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'blob:http%3A//your.blob.url.here', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
  if (this.status == 200) {
    var myBlob = this.response;
    // myBlob is now the blob that the object URL pointed to.
  }
};
xhr.send();

Update (2018): For situations where ES5 can safely be used, Joe has a simpler ES5-based answer below.


Maybe someone finds this useful when working with React/Node/Axios. I used this for my Cloudinary image upload feature with react-dropzone on the UI.

    axios({
        method: 'get',
        url: file[0].preview, // blob url eg. blob:http://127.0.0.1:8000/e89c5d87-a634-4540-974c-30dc476825cc
        responseType: 'blob'
    }).then(function(response){
         var reader = new FileReader();
         reader.readAsDataURL(response.data); 
         reader.onloadend = function() {
             var base64data = reader.result;
             self.props.onMainImageDrop(base64data)
         }

    })

Using fetch for example like below:

 fetch(<"yoururl">, {
    method: 'GET',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + <your access token if need>
    },
       })
.then((response) => response.blob())
.then((blob) => {
// 2. Create blob link to download
 const url = window.URL.createObjectURL(new Blob([blob]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `sample.xlsx`);
 // 3. Append to html page
 document.body.appendChild(link);
 // 4. Force download
 link.click();
 // 5. Clean up and remove the link
 link.parentNode.removeChild(link);
})

You can paste in on Chrome console to test. the file with download with 'sample.xlsx' Hope it can help!


See Getting BLOB data from XHR request which points out that BlobBuilder doesn't work in Chrome so you need to use:

xhr.responseType = 'arraybuffer';

The problem with fetching the blob URL again is that this will create a full copy of the Blob's data, and so instead of having it only once in memory, you'll have it twice. With big Blobs this can blow your memory usage quite quickly.

It's rather unfortunate that the File API doesn't give us access to the currently linked Blobs, certainly they thought web-authors should store that Blob themselves at creation time anyway, which is true:

The best here is to store the object you used when creating the blob:// URL.

If you are afraid this would prevent the Blob from being Garbage Collected, you're right, but so does the blob:// URL in the first place, until you revoke it. So holding yourself a pointer to that Blob won't change a thing.

But for those who aren't responsible for the creation of the blob:// URI (e.g because a library made it), we can still fill that API hole ourselves by overriding the default URL.createObjectURL and URL.revokeObjectURL methods so that they do store references to the object passed.

Be sure to call this function before the code that does generate the blob:// URI is called.

// Adds an URL.getFromObjectURL( <blob:// URI> ) method
// returns the original object (<Blob> or <MediaSource>) the URI points to or null
(() => {
  // overrides URL methods to be able to retrieve the original blobs later on
  const old_create = URL.createObjectURL;
  const old_revoke = URL.revokeObjectURL;
  Object.defineProperty(URL, 'createObjectURL', {
    get: () => storeAndCreate
  });
  Object.defineProperty(URL, 'revokeObjectURL', {
    get: () => forgetAndRevoke
  });
  Object.defineProperty(URL, 'getFromObjectURL', {
    get: () => getBlob
  });
  const dict = {};

  function storeAndCreate(blob) {
    const url = old_create(blob); // let it throw if it has to
    dict[url] = blob;
    return url
  }

  function forgetAndRevoke(url) {
    old_revoke(url);
    try {
      if(new URL(url).protocol === 'blob:') {
        delete dict[url];
      }
    } catch(e){}
  }

  function getBlob(url) {
    return dict[url] || null;
  }
})();

//  Usage:
const blob = new Blob( ["foo"] );
const url = URL.createObjectURL( blob );
console.log( url );
const retrieved = URL.getFromObjectURL( url );
console.log( "retrieved Blob is Same Object?", retrieved === blob );
fetch( url ).then( (resp) => resp.blob() )
  .then( (fetched) => console.log( "fetched Blob is Same Object?", fetched === blob ) );

And an other advantage is that it can even retrieve MediaSource objects, while the fetching solutions would just err in that case.