Wie erhalte ich eine Datei oder einen Blob von einer Objekt-URL?

127

Ich erlaube dem Benutzer, Bilder per Drag & Drop und anderen Methoden auf eine Seite zu laden. Wenn ein Bild gelöscht wird, URL.createObjectURLkonvertiere ich es in eine Objekt-URL, um das Bild anzuzeigen. Ich widerrufe die URL nicht, da ich sie wieder verwende.

Wenn es also an der Zeit ist, ein FormDataObjekt zu erstellen, damit sie ein Formular mit einem dieser Bilder hochladen können, kann ich diese Objekt-URL dann auf irgendeine Weise wieder in eine umkehren Bloboder Filesie dann an eine anhängen FormDataObjekt?

BrianFreud
quelle
Denken Sie nicht an die beiden vorherigen Kommentare - alles, was Sie tun müssen, ist eine XMLHttpRequestan die Blob-URL zu senden .
Gengkev
2
Warum speichern Sie die Originaldateiobjekte nicht einfach irgendwo, verwenden Sie dann die Objekt-URL, um sie anzuzeigen, und verwenden Sie beim Senden des Formulars die Originaldateien?
user764754
@ user764754, da der Versuch, die URL der vom Benutzer hochgeladenen Datei abzurufen, als "C: \ fakepath" angezeigt wird
Malcolm Salvador

Antworten:

86

Moderne Lösung:

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

Die URL kann eine Objekt-URL oder eine normale URL sein.


quelle
3
Nett. Ich bin froh zu sehen, dass ES5 solche Dinge einfacher macht.
BrianFreud
11
Und wenn Sie direkt eine Datei aus dem Versprechen erhalten möchten, können Sie eine Datei wie folgt generieren. let file = await fetch(url).then(r => r.blob()).then(blobFile => new File([blobFile], "fileNameGoesHere", { type: "image/png" })
Dbakiu
3
Leider funktioniert diese Lösung in Chrome nicht. Der Browser kann diese URL nicht laden.
Waldgeist
Waldgeist, hast du es in createObjectUrl () eingeschlossen?
Matt Fletcher
73

Wie Gengkev in seinem obigen Kommentar anspielt, scheint es der beste / einzige Weg zu sein, dies mit einem asynchronen xhr2-Aufruf zu tun:

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): Für Situationen, in denen ES5 sicher verwendet werden kann, hat Joe unten eine einfachere ES5-basierte Antwort.

BrianFreud
quelle
19
Wann würden Sie jemals eine objectURL haben, die nicht lokal für die aktuelle Domäne und den aktuellen Bereich ist?
BrianFreud
4
Ich habe es genauso gemacht wie oben, aber 404 wurde mit dem xhr nicht gefunden. Was ist los?
Albert Yu
Bitte beachten Sie, dass einige Browser (lesen Sie den alten IE ...), wenn Sie diese verarbeiten müssen, siehe Beitrag stackoverflow.com/questions/17657184/…
mraxus
4
@BrianFreud "Wann würden Sie jemals eine objectURL haben, die nicht lokal für die aktuelle Domäne und den aktuellen Bereich ist?" In meinem Fall versuche ich, einem Amazon S3-Blob einen anderen Dateinamen zu geben, der derzeit eine "Anleitung" für den S3 ohne Erweiterung ist. In meinem Fall verwende ich also einen domänenübergreifenden Anruf.
Wagner Bertolini Junior
6
"Objekt-URLs sind URLs, die auf Dateien auf der Festplatte verweisen." ObjectURLs können per Definition nur lokal sein.
BrianFreud
12

Vielleicht findet jemand dies nützlich, wenn er mit React / Node / Axios arbeitet. Ich habe dies für meine Cloudinary-Funktion zum Hochladen von Bildern react-dropzoneauf der Benutzeroberfläche verwendet.

    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)
         }

    })
spedy
quelle
1
Funktioniert dies für domänenübergreifende Anfragen? Twitter-Videos haben eine Blob-URL. Ich muss in der Lage sein, das Blob-Objekt zu erfassen, auf das die Blob-URL zeigt. Ich verwende Fetch API im Browser, was mir diesen Fehler gibt - Refused to connect to 'blob:https://twitter.com/9e00aec3-6729-42fb-b5a7-01f50be302fa' because it violates the following Content Security Policy directive: "connect-src . Könnten Sie einen Hinweis haben, was ich möglicherweise falsch mache / nicht bekomme?
Gdadsriver
Ich konnte diesen Einzeiler verwenden, um das Ergebnis mit dem Blob als Dateneigenschaft zu erhalten: const result = warte auf axios.get (url, {responseType: "blob"});
Noah Stahl
4

Verwenden Sie Fetch zum Beispiel wie folgt:

 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);
})

Sie können zum Testen in die Chrome-Konsole einfügen. die Datei mit Download mit 'sample.xlsx' Hoffe es kann helfen!

user3843418
quelle
Ich denke, das OP hat nach der Konvertierung einer Blob-URL in eine tatsächliche Datei / einen Blob gefragt und nicht umgekehrt.
Abhishek Ghosh
3

Leider passt die Antwort von @ BrianFreud nicht zu meinen Bedürfnissen, ich hatte ein etwas anderes Bedürfnis und ich weiß, dass dies nicht die Antwort auf die Frage von @ BrianFreud ist, aber ich lasse sie hier, weil viele Personen mit demselben Bedürfnis hierher gekommen sind. Ich brauchte etwas wie "Wie bekomme ich eine Datei oder einen Blob von einer URL?", Und die aktuell richtige Antwort entspricht nicht meinen Anforderungen, da sie nicht domänenübergreifend ist.

Ich habe eine Website, die Bilder aus einem Amazon S3 / Azure-Speicher verwendet, und dort speichere ich Objekte mit eindeutigen Kennungen:

Beispiel: http: //****.blob.core.windows.net/systemimages/bf142dc9-0185-4aee-a3f4-1e5e95a09bcf

Einige dieser Bilder sollten von unserer Systemschnittstelle heruntergeladen werden. Um zu vermeiden, dass dieser Datenverkehr über meinen HTTP-Server geleitet wird, habe ich beschlossen, eine direkte Anfrage im Browser des Benutzers zu stellen und der Datei die lokale Verarbeitung zu geben, um der Datei einen echten Namen zu geben, da für diese Objekte keine Sicherheit erforderlich ist (außer durch Domänenfilterung) Erweiterung.

Um dies zu erreichen, habe ich diesen großartigen Artikel von Henry Algus verwendet: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/

1. Erster Schritt: Fügen Sie jquery binäre Unterstützung hinzu

/**
*
* jquery.binarytransport.js
*
* @description. jQuery ajax transport for making binary data type requests.
* @version 1.0 
* @author Henry Algus <[email protected]>
*
*/

// use this transport for "binary" data type
$.ajaxTransport("+binary", function (options, originalOptions, jqXHR) {
    // check for conditions and support for blob / arraybuffer response type
    if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob))))) {
        return {
            // create new XMLHttpRequest
            send: function (headers, callback) {
                // setup all variables
                var xhr = new XMLHttpRequest(),
        url = options.url,
        type = options.type,
        async = options.async || true,
        // blob or arraybuffer. Default is blob
        dataType = options.responseType || "blob",
        data = options.data || null,
        username = options.username || null,
        password = options.password || null;

                xhr.addEventListener('load', function () {
                    var data = {};
                    data[options.dataType] = xhr.response;
                    // make callback and send data
                    callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
                });

                xhr.open(type, url, async, username, password);

                // setup custom headers
                for (var i in headers) {
                    xhr.setRequestHeader(i, headers[i]);
                }

                xhr.responseType = dataType;
                xhr.send(data);
            },
            abort: function () {
                jqXHR.abort();
            }
        };
    }
});

2. Zweiter Schritt: Stellen Sie eine Anfrage mit diesem Transporttyp.

function downloadArt(url)
{
    $.ajax(url, {
        dataType: "binary",
        processData: false
    }).done(function (data) {
        // just my logic to name/create files
        var filename = url.substr(url.lastIndexOf('/') + 1) + '.png';
        var blob = new Blob([data], { type: 'image/png' });

        saveAs(blob, filename);
    });
}

Jetzt können Sie den erstellten Blob so verwenden, wie Sie möchten. In meinem Fall möchte ich ihn auf der Festplatte speichern.

3. Optional: Speichern Sie die Datei mit FileSaver auf dem Computer des Benutzers

Ich habe FileSaver.js verwendet, um die heruntergeladene Datei auf der Festplatte zu speichern. Wenn Sie dies benötigen, verwenden Sie bitte diese Javascript-Bibliothek:

https://github.com/eligrey/FileSaver.js/

Ich erwarte, dass dies anderen mit spezifischeren Bedürfnissen hilft.

Wagner Bertolini Junior
quelle
1
ObjectURLs sind per Definition lokal. Objekt-URLs sind URLs, die auf Dateien auf der Festplatte verweisen. Da es keine domänenübergreifende objectURL gibt, kombinieren Sie zwei verschiedene Konzepte und damit Ihr Problem mit der angegebenen Lösung.
BrianFreud
1
@BrianFreud Ich habe es verstanden, dass dies nicht genau die Antwort auf diese Frage ist. Aber ich denke immer noch, dass es eine gute Antwort ist, zu gehen, da ich hier nach der Antwort auf eine etwas andere Frage gesucht habe: "Wie bekomme ich eine Datei oder einen Blob von einer URL?". Wenn Sie Ihre eigene Antwort überprüfen, gibt es 10 Upvotes zu 'Es funktioniert nicht bei domänenübergreifenden Anfragen. '. Also kamen mehr als 10 Personen hierher, um danach zu suchen. Ich beschloss dann, es hier zu lassen.
Wagner Bertolini Junior
Das Problem ist, dass Ihre Antwort diese Frage wissentlich nicht beantwortet. Eine normale URL und eine Objekt-URL sind zwei völlig verschiedene Dinge. In Bezug auf die Anzahl der Upvotes zu "Es funktioniert nicht bei domänenübergreifenden Anfragen." Würden Sie nicht besser erklären, warum dies hier buchstäblich unmöglich ist, und auf einen Punkt verweisen, der die Antwort für normale URLs zeigt als Dinge hier zu verwirren, indem normale URLs und Objekt-URLs zusammengeführt werden?
BrianFreud
@BrianFreud zögern Sie nicht, meine Antwort zu bearbeiten. Ich werde über das Thema lernen, vielleicht habe ich falsch verstanden, was eine "objectURL" gegenüber einer "object URL" ist ... Englisch ist nicht meine Muttersprache. Ich werde über das Thema recherchieren, um eine bessere Antwort zu geben. Aber ich denke, das sind andere, die hierher kommen und nach etwas anderem suchen. Ich habe nicht nach "objectURL" gesucht, um hierher zu kommen, das war mein Punkt zuvor. Aber ich habe dich auch.
Wagner Bertolini Junior
2

Wenn Sie die Datei trotzdem in einer Zeichenfläche anzeigen, können Sie den Zeichenflächeninhalt auch in ein Blob-Objekt konvertieren.

canvas.toBlob(function(my_file){
  //.toBlob is only implemented in > FF18 but there is a polyfill 
  //for other browsers https://github.com/blueimp/JavaScript-Canvas-to-Blob
  var myBlob = (my_file);
})
Thilo
quelle
2
Beachten Sie, dass Sie dadurch nicht dieselbe Originaldatei zurückerhalten . Es wird im laufenden Betrieb eine neue Bilddatei erstellt. Als ich das vor ein paar Jahren das letzte Mal getestet habe, habe ich festgestellt, dass die neue Bilddatei zumindest in Chrome überhaupt nicht komprimiert ist - ich hatte 10.000 JPGs, die sich in 2,5 MB JPGs verwandelten.
BrianFreud