Bagaimana cara mendapatkan file atau blob dari URL objek?

127

Saya mengizinkan pengguna untuk memuat gambar ke halaman melalui drag & drop dan metode lainnya. Saat gambar dijatuhkan, saya menggunakanURL.createObjectURL untuk mengonversi ke URL objek untuk menampilkan gambar. Saya tidak mencabut url, karena saya menggunakannya kembali.

Jadi, ketika tiba saatnya untuk membuat FormDataobjek sehingga saya dapat mengizinkan mereka mengunggah formulir dengan salah satu gambar di dalamnya, adakah cara agar saya dapat membalikkan URL Objek itu kembali menjadi Blobatau Filejadi saya dapat menambahkannya ke FormDataobyek?

BrianFreud
sumber
lupakan tentang dua komentar sebelumnya - yang perlu Anda lakukan hanyalah mengirim XMLHttpRequestke URL blob.
gengkev
2
Mengapa tidak hanya menyimpan objek file asli di suatu tempat, kemudian menggunakan URL objek untuk menampilkannya dan pada form submit gunakan file asli?
pengguna764754
@ user764754 karena mencoba mendapatkan URL dari file yang diunggah oleh pengguna ditampilkan sebagai "C: \ fakepath"
Malcolm Salvador

Jawaban:

89

Solusi modern:

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

Url dapat berupa url objek atau url normal.


sumber
3
Bagus. Senang melihat ES5 membuat hal-hal seperti ini lebih sederhana.
BrianFreud
11
Dan jika Anda ingin mendapatkan file dari promise secara langsung, Anda dapat membuat file sebagai berikut. let file = await fetch(url).then(r => r.blob()).then(blobFile => new File([blobFile], "fileNameGoesHere", { type: "image/png" })
dbakiu
3
Sayangnya, solusi ini tidak berfungsi untuk saya di Chrome. Browser gagal memuat URL ini.
waldgeist
Waldgeist, apakah Anda membungkusnya di createObjectUrl ()?
Matt Fletcher
73

Seperti yang disinggung gengkev dalam komentarnya di atas, sepertinya cara terbaik / satu-satunya untuk melakukan ini adalah dengan panggilan xhr2 asinkron:

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

Pembaruan (2018): Untuk situasi di mana ES5 dapat digunakan dengan aman, Joe memiliki jawaban berbasis ES5 yang lebih sederhana di bawah ini.

BrianFreud
sumber
19
Kapan Anda pernah memiliki objectURL yang tidak lokal untuk domain dan cakupan saat ini?
BrianFreud
4
saya melakukannya sama seperti di atas, tetapi mendapat 404 tidak ditemukan dengan xhr tersebut. apa yang sedang terjadi?
albert yu
Harap perhatikan bahwa beberapa browser (baca IE lama ...), jika Anda perlu menanganinya, lihat posting stackoverflow.com/questions/17657184/…
mraxus
4
@BrianFreud "Kapan Anda pernah memiliki objectURL yang tidak lokal untuk domain dan cakupan saat ini?" Dalam kasus saya, saya mencoba memberi gumpalan Amazon S3 nama file yang berbeda, yang saat ini merupakan "panduan" di S3 tanpa ekstensi. Jadi, dalam kasus saya, saya menggunakan panggilan lintas domain.
Wagner Bertolini Junior
6
"URL Objek adalah URL yang mengarah ke file di disk." ObjectURL menurut definisi hanya bisa lokal.
BrianFreud
13

Mungkin seseorang menganggap ini berguna saat bekerja dengan React / Node / Axios. Saya menggunakan ini untuk fitur unggah gambar Cloudinary saya dengan react-dropzonedi 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)
         }

    })
spedy
sumber
2
Apakah ini berfungsi untuk permintaan lintas domain? Video Twitter memiliki URL blob. Saya harus bisa mengumpulkan objek blob yang ditunjukkan oleh URL blob. Saya menggunakan fetch api di browser, yang memberikan saya kesalahan ini - Refused to connect to 'blob:https://twitter.com/9e00aec3-6729-42fb-b5a7-01f50be302fa' because it violates the following Content Security Policy directive: "connect-src . Bisakah Anda mendapatkan petunjuk apa yang mungkin saya lakukan salah / tidak saya dapatkan?
gdadsriver
Saya bisa menggunakan satu baris ini untuk mendapatkan hasil dengan blob sebagai properti data: const result = await axios.get (url, {responseType: "blob"});
Noah Stahl
4

Lihat Mendapatkan data BLOB dari permintaan XHR yang menunjukkan bahwa BlobBuilder tidak berfungsi di Chrome sehingga Anda perlu menggunakan:

xhr.responseType = 'arraybuffer';
Michel Floyd
sumber
4

Menggunakan fetch misalnya seperti di bawah ini:

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

Anda dapat menempel di konsol Chrome untuk menguji. file dengan unduhan dengan 'sample.xlsx' Semoga dapat membantu!

pengguna3843418
sumber
Saya pikir OP bertanya tentang mengubah url gumpalan menjadi file / gumpalan sebenarnya, daripada sebaliknya.
Abhishek Ghosh
3

Sayangnya jawaban @ BrianFreud tidak sesuai dengan kebutuhan saya, saya memiliki kebutuhan yang sedikit berbeda, dan saya tahu itu bukan jawaban untuk pertanyaan @ BrianFreud, tetapi saya meninggalkannya di sini karena banyak orang datang ke sini dengan kebutuhan yang sama. Saya memerlukan sesuatu seperti 'Bagaimana cara mendapatkan file atau blob dari URL?', Dan jawaban yang benar saat ini tidak sesuai dengan kebutuhan saya karena tidak lintas domain.

Saya memiliki situs web yang menggunakan gambar dari Amazon S3 / Azure Storage, dan di sana saya menyimpan objek yang diberi nama dengan pengidentifikasi unik:

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

Beberapa gambar ini harus diunduh dari antarmuka sistem kami. Untuk menghindari melewatkan lalu lintas ini melalui server HTTP saya, karena objek ini tidak memerlukan keamanan apa pun untuk diakses (kecuali dengan pemfilteran domain), saya memutuskan untuk membuat permintaan langsung di browser pengguna dan menggunakan pemrosesan lokal untuk memberikan nama asli pada file tersebut dan perpanjangan.

Untuk mencapai itu saya telah menggunakan artikel hebat ini dari Henry Algus: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/

1. Langkah pertama: Tambahkan dukungan biner ke jquery

/**
*
* 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. Langkah kedua: Buat permintaan menggunakan jenis transportasi ini.

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

Sekarang Anda dapat menggunakan Blob yang dibuat sesuai keinginan, dalam kasus saya, saya ingin menyimpannya ke disk.

3. Opsional: Simpan file di komputer pengguna menggunakan FileSaver

Saya telah menggunakan FileSaver.js untuk menyimpan file yang diunduh ke disk, jika Anda perlu melakukannya, gunakan pustaka javascript ini:

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

Saya berharap ini dapat membantu orang lain dengan kebutuhan yang lebih spesifik.

Wagner Bertolini Junior
sumber
1
ObjectURLs menurut definisi lokal. URL objek adalah URL yang mengarah ke file di disk. Mengingat bahwa tidak ada yang namanya objectURL lintas domain, Anda menyisir dua konsep berbeda, jadi masalah Anda menggunakan solusi yang diberikan.
BrianFreud
1
@ BrianFud Saya mengerti bahwa itu bukan jawaban dari pertanyaan ini. Tetapi saya masih berpikir bahwa itu adalah jawaban yang bagus untuk pergi karena saya tiba di sini mencari jawaban dari pertanyaan yang sedikit berbeda 'Bagaimana cara mendapatkan file atau blob dari URL?'. Jika Anda memeriksa jawaban Anda sendiri, ada 10 suara positif pada 'Tidak berfungsi jika ada permintaan lintas domain. '. Jadi lebih dari 10 orang datang ke sini untuk mencari itu. Saya kemudian memutuskan untuk meninggalkannya di sini.
Wagner Bertolini Junior
Masalahnya adalah, jawaban Anda secara sadar tidak menjawab pertanyaan ini. URL normal dan URL objek adalah dua hal yang sangat berbeda. Mengenai # suara positif pada "Ini tidak berfungsi dalam kasus permintaan lintas domain.", Bukankah menurut Anda lebih baik menjelaskan mengapa hal itu benar-benar tidak mungkin di sini, dan untuk menunjukkan ke suatu tempat yang memang menunjukkan jawaban untuk URL normal, bukan daripada membingungkan di sini dengan menggabungkan URL normal dan URL objek?
BrianFud
@BrianFreud jangan ragu untuk menyarankan pengeditan pada jawaban saya. Saya akan belajar tentang subjek, mungkin saya salah paham apa itu "objectURL" vs sebuah "object URL" ... Bahasa Inggris bukan bahasa ibu saya. Saya akan melakukan penelitian tentang subjek untuk memberikan jawaban yang lebih baik. Tapi saya pikir ada orang lain yang datang ke sini mencari sesuatu yang berbeda. Saya tidak mencari "objectURL" untuk sampai ke sini, itu maksud saya sebelumnya. Tapi aku juga punya kamu.
Wagner Bertolini Junior
2

Jika Anda tetap menampilkan file di kanvas, Anda juga dapat mengonversi konten kanvas menjadi objek blob.

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
sumber
2
Perhatikan bahwa itu tidak benar-benar mengembalikan file asli yang sama ; itu membuat file gambar baru dengan cepat. Ketika saya terakhir mengujinya beberapa tahun yang lalu, saya menemukan bahwa setidaknya di Chrome, file gambar baru tidak dikompresi sama sekali - saya memiliki 10k jpg yang berubah menjadi 2,5 mb jpg.
BrianFreud