Bir nesne URL'sinden bir dosya veya blob nasıl alınır?


127

Kullanıcının bir sayfaya sürükle-bırak ve diğer yöntemlerle resimleri yüklemesine izin veriyorum. Bir görüntü düştüğünde, URL.createObjectURLgörüntüyü görüntülemek için bir nesne URL'sine dönüştürmek için kullanıyorum . Yeniden kullandığım için url'yi iptal etmiyorum.

Dolayısıyla, bir FormDatanesne oluşturma zamanı geldiğinde , bu resimlerden birini içeren bir form yüklemelerine izin verebiliyorum, bu Nesne URL'sini bir Blobveya Filedaha sonra bir FormDatanesne?


önceki iki yorumu boşverin - tek yapmanız gereken XMLHttpRequestblob URL'sine bir göndermektir .
gengkev

2
Neden orijinal dosya nesnelerini bir yerde depolayıp, sonra bunları görüntülemek için nesne URL'sini ve form gönderirken orijinal dosyaları kullanmıyorsunuz?
user764754

@ user764754, çünkü kullanıcı tarafından yüklenen dosyanın URL'sini almaya çalışırken "C: \ fakepath" olarak görüntüleniyor
Malcolm Salvador

Yanıtlar:


89

Modern çözüm:

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

URL, bir nesne url'si veya normal bir url olabilir.


3
Güzel. ES5'in bu tür şeyleri daha basit hale getirmesine sevindim.
BrianFreud

11
Ve doğrudan sözden bir dosya almak istiyorsanız, aşağıdaki gibi bir dosya oluşturabilirsiniz. let file = await fetch(url).then(r => r.blob()).then(blobFile => new File([blobFile], "fileNameGoesHere", { type: "image/png" })
dbakiu

3
Ne yazık ki bu çözüm Chrome'da benim için çalışmıyor. Tarayıcı bu URL'yi yükleyemiyor.
waldgeist

Waldgeist, bunu createObjectUrl () içine sardın mı?
Matt Fletcher

73

Gengkev'in yukarıdaki yorumunda ima ettiği gibi, bunu yapmanın en iyi / tek yolu eşzamansız bir xhr2 çağrısıdır:

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

Güncelleme (2018): ES5'in güvenle kullanılabileceği durumlar için, Joe'nun aşağıda daha basit bir ES5 tabanlı cevabı var.


19
Geçerli etki alanı ve kapsam için yerel olmayan bir objectURL ne zaman olur ?
BrianFreud

4
Yukarıdakinin aynısını yaptım, ancak xhr ile 404 bulunamadı. neler oluyor?
albert yu

Lütfen bazı tarayıcıların (eski IE'yi okuyun ...), bunları işlemeniz gerekiyorsa, stackoverflow.com/questions/17657184/…
postasına

4
@BrianFreud "Ne zaman mevcut etki alanı ve kapsamı için yerel olmayan bir objectURL'ye sahip olursunuz?" Benim durumumda bir Amazon S3 blobuna farklı bir dosya adı vermeye çalışıyorum, bu şu anda S3'te uzantısız bir "kılavuz". Yani, benim durumumda alanlar arası arama kullanıyorum.
Wagner Bertolini Junior

6
"Nesne URL'leri, diskteki dosyalara işaret eden URL'lerdir." Tanım gereği ObjectURL'ler yalnızca yerel olabilir.
BrianFreud

13

Belki birisi React / Node / Axios ile çalışırken bunu faydalı bulabilir. Bunu react-dropzone, kullanıcı arayüzünde Cloudinary görüntü yükleme özelliğim için kullandım .

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

    })

2
Bu, etki alanları arası istekler için çalışıyor mu? Twitter videolarının blob URL'si var. Blob URL'sinin işaret ettiği blob nesnesini toplayabilmem gerekiyor. Tarayıcıda getirme api kullanıyorum, bu da bana bu hatayı veriyor - Refused to connect to 'blob:https://twitter.com/9e00aec3-6729-42fb-b5a7-01f50be302fa' because it violates the following Content Security Policy directive: "connect-src . Neyi yanlış yaptığım / almadığım konusunda bir ipucu alabilir misin?
gdadsriver

Veri özelliği olarak blob ile sonucu elde etmek için bu tek satırlık yazıyı kullanabildim: const sonuç = await axios.get (url, {responseType: "blob"});
Nuh Stahl


4

Örneğin aşağıdaki gibi getirme işlevini kullanma:

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

Test etmek için Chrome konsoluna yapıştırabilirsiniz. dosya 'sample.xlsx' ile indirilebilir Umarım yardımcı olabilir!


Bence OP bir blob url'sini gerçek dosya / blob'a dönüştürmeyi sordu, tersi değil.
Abhishek Ghosh

3

Maalesef @ BrianFreud'un cevabı ihtiyaçlarıma uymuyor, biraz farklı bir ihtiyacım vardı ve bunun @ BrianFreud'un sorusu için cevabı olmadığını biliyorum, ama burada bırakıyorum çünkü birçok insan aynı ihtiyacımla buraya geldi. 'Bir URL'den bir dosya veya blob nasıl alınır?' Gibi bir şeye ihtiyacım vardı ve mevcut doğru cevap, alanlar arası olmadığı için ihtiyaçlarıma uymuyor.

Amazon S3 / Azure Depolamasından görüntüler tüketen bir web sitem var ve burada benzersiz tanımlayıcılarla adlandırılmış nesneleri depoluyorum:

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

Bu resimlerden bazıları sistem arayüzümüzden indirilmelidir. Bu trafiğin HTTP sunucumdan geçmesini önlemek için, bu nesnelere erişim için herhangi bir güvenlik gerektirmediğinden (etki alanı filtreleme hariç), kullanıcının tarayıcısından doğrudan bir istekte bulunmaya ve dosyaya gerçek bir ad vermek için yerel işlemeyi kullanmaya karar verdim ve uzantı.

Bunu başarmak için Henry Algus'un bu harika makalesini kullandım: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/

1. İlk adım: jquery'ye ikili destek ekleyin

/**
*
* jquery.binarytransport.js
*
* @description. jQuery ajax transport for making binary data type requests.
* @version 1.0 
* @author Henry Algus <henryalgus@gmail.com>
*
*/

// 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. İkinci adım: Bu taşıma türünü kullanarak bir istekte bulunun.

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

Şimdi istediğiniz gibi oluşturulan Blob'u kullanabilirsiniz, benim durumumda onu diske kaydetmek istiyorum.

3. İsteğe bağlı: Dosyayı FileSaver'ı kullanarak kullanıcının bilgisayarına kaydedin

İndirilen dosyayı diske kaydetmek için FileSaver.js'yi kullandım, bunu yapmanız gerekiyorsa, lütfen şu javascript kitaplığını kullanın:

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

Bunun daha özel ihtiyaçları olan başkalarına yardımcı olmasını bekliyorum.


1
ObjectURL'ler tanım gereği yereldir. Nesne URL'leri, diskteki dosyalara işaret eden URL'lerdir. Etki alanları arası nesne URL'si diye bir şey olmadığı göz önüne alındığında, iki farklı kavramı, dolayısıyla verilen çözümü kullanarak probleminizi tarıyorsunuz.
BrianFreud

1
@BrianFreud Anladım, bu tam olarak bu sorunun cevabı değil. Ama yine de, buraya biraz farklı bir 'URL'den dosya veya blob nasıl alınır?' Sorusunun cevabını aradığım için ayrılmak için iyi bir cevap olduğunu düşünüyorum. Kendi cevabınızı kontrol ederseniz, 'Etki alanları arası isteklerde işe yaramaz. '. Yani onu arayan 10'dan fazla kişi buraya geldi. Sonra onu burada bırakmaya karar verdim.
Wagner Bertolini Junior

Sorun şu ki, cevabınız bilerek bu soruya cevap vermiyor. Normal bir URL ve bir nesne URL'si tamamen farklı iki şeydir. "Etki alanları arası isteklerde işe yaramaz" konusundaki olumlu oyların sayısı ile ilgili olarak, burada bunun neden tam anlamıyla imkansız olduğunu açıklamak ve bunun yerine normal URL'lerin yanıtını gösteren bir yere işaret etmek daha iyi olmaz mıydı? burada normal URL'leri ve nesne URL'lerini karıştırarak kafa karıştırmaktan mı?
BrianFreud

@BrianFreud cevabımda bir düzenleme önermekten çekinmeyin. Konu hakkında çalışacağım, belki bir "nesne URL'si" ile "nesne URL'si" nin ne olduğunu yanlış anladım ... İngilizce benim anadilim değil. Daha iyi cevap verebilmek için konu ile ilgili bir araştırma yapacağım. Ama bence buraya farklı bir şey arayanlar geliyor. Buraya gelmek için "objectURL" araması yapmadım, daha önce amacım buydu. Ama ben de seni yakaladım.
Wagner Bertolini Junior

2

Dosyayı yine de bir tuvalde gösterirseniz, tuval içeriğini bir blob nesnesine de dönüştürebilirsiniz.

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

2
Bunun size aynı orijinal dosyayı geri vermediğini unutmayın ; anında yeni bir görüntü dosyası oluşturuyor. Bunu birkaç yıl önce en son test ettiğimde, en azından Chrome'da yeni görüntü dosyasının hiç sıkıştırılmadığını keşfettim - 10k jpgs'nin 2.5 mb jpgs'ye dönüştüğünü gördüm.
BrianFreud
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.