Як отримати файл або крапку з URL-адреси об’єкта?


127

Я дозволяю користувачу завантажувати зображення на сторінку за допомогою перетягування та інших методів. Коли зображення падає, я використовую URL.createObjectURLдля перетворення URL-адреси об'єкта для відображення зображення. Я не відкликаю URL-адресу, оскільки я його повторно використовую.

Отже, коли настає час створити FormDataоб’єкт, щоб я міг дозволити їм завантажувати форму з одним із цих зображень у ній, чи є якимось чином я зможу повернути цю об’єктну URL-адресу назад у Blobабо Fileтак, щоб потім я додати її до FormDataоб’єкт?


Не забувайте про попередні два коментарі - все, що вам потрібно зробити, це надіслати XMLHttpRequestURL-адресу краплі.
gengkev

2
Чому б просто не зберігати десь оригінальні файлові об’єкти, а потім використовувати URL-адресу об’єкта для їх відображення та під час подання форми використовувати оригінальні файли?
користувач764754

@ user764754, оскільки спроба отримати URL-адресу завантаженого файлу користувачем відображається як "C: \ fakepath"
Малькольм Сальвадор

Відповіді:


88

Сучасне рішення:

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

URL може бути об’єктом URL або звичайним URL.


3
Приємно. Радий бачити, що ES5 робить такі речі простішими.
BrianFreud

11
І якщо ви хочете безпосередньо отримати файл із обіцянки, ви можете створити файл наступним чином. let file = await fetch(url).then(r => r.blob()).then(blobFile => new File([blobFile], "fileNameGoesHere", { type: "image/png" })
dbakiu

3
На жаль, це рішення не працює для мене в Chrome. Браузер не може завантажити цю URL-адресу.
вальджіст

Вальджейсте, ти закрутив це у createObjectUrl ()?
Метт Флетчер

73

Як наголошує gengkev у своєму коментарі вище, це виглядає як найкращий / єдиний спосіб зробити це за допомогою виклику async xhr2:

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

Оновлення (2018). У випадках, коли ES5 можна безпечно використовувати, Joe має простішу відповідь на основі ES5 нижче.


19
Коли у вас коли-небудь з'явиться об’єктURL, який не локальний для поточного домену та сфери застосування?
BrianFreud

4
Я зробив це так само, як вище, але отримав 404, не знайдений з xhr. що відбувається?
Альбер Ю

Будь ласка , зверніть увагу , що деякі браузери (читай старий IE ...), якщо вам потрібно працювати з тими , см пост stackoverflow.com/questions/17657184 / ...
mraxus

4
@BrianFreud "Коли у вас коли-небудь з'явиться об'єктURL, який не є локальним для поточного домену та області дії?" У моєму випадку я намагаюся надати Amazon S3 blob інше ім'я файлу, яке в даний час є "орієнтиром" для S3 без розширення. Тож у моєму випадку я використовую міждоменний дзвінок.
Вагнер Бертоліні Юніор

6
"Об'єктні URL-адреси - це URL-адреси, які вказують на файли на диску." Об'єктиURL за визначенням можуть бути лише локальними.
BrianFreud

12

Можливо, хтось вважає це корисним під час роботи з React / Node / Axios. Я використав це для моєї функції завантаження зображень у облачному react-dropzoneінтерфейсі за допомогою інтерфейсу користувача.

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

    })

1
Чи працює це для міждоменних запитів? У відео на Twitter є URL-адреса блобу. Мені потрібно вміти збирати об'єкт blob, на який вказує URL-адреса blob. Я використовую інструмент добування api у браузері, який дає мені цю помилку - Refused to connect to 'blob:https://twitter.com/9e00aec3-6729-42fb-b5a7-01f50be302fa' because it violates the following Content Security Policy directive: "connect-src . Чи можете ви підказати, що я можу зробити неправильно / не отримати?
gdadsriver

Мені вдалося скористатись цим одноклассником, щоб отримати результат із blob як властивість даних: const result = await axios.get (url, {responseType: "blob"});
Ной Шталь


4

Використовуючи приклад, наприклад, як нижче:

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

Ви можете вставити на консоль Chrome для тестування. файл із завантаженням з "sample.xlsx" Сподіваюся, що це може допомогти!


Я думаю, що ОП запитала про перетворення URL-адреси крапки у фактичний файл / блоб, а не навпаки.
Abhishek Ghosh

3

На жаль, відповідь @ BrianFreud не відповідає моїм потребам, у мене була дещо інша потреба, і я знаю, що це не відповідь на питання @ BrianFreud, але я залишаю це, тому що багато людей потрапили сюди з моєю такою ж потребою. Мені знадобилося щось на кшталт "Як отримати файл або крапку з URL-адреси?", І поточна правильна відповідь не відповідає моїм потребам, оскільки це не крос-домен.

У мене є веб-сайт, який використовує зображення з Amazon S3 / Azure Storage, і там я зберігаю об’єкти, названі унікальними ідентифікаторами:

зразок: http: //****.blob.core.windows.net/systemimages/bf142dc9-0185-4aee-a3f4-1e5e95a09bcf

Деякі з цих зображень слід завантажити з нашого системного інтерфейсу. Щоб уникнути передачі цього трафіку через мій сервер HTTP, оскільки цей об’єкт не потребує доступу до будь-якої безпеки (крім фільтрації домену), я вирішив зробити прямий запит у веб-переглядачі користувача та використати локальну обробку, щоб надати файлу справжнє ім'я та розширення.

Щоб досягти того, що я використав цю чудову статтю від Генрі Альгуса: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/

1. Перший крок: Додайте бінарну підтримку до jquery

/**
*
* 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. Другий крок: оформити запит, використовуючи цей вид транспорту.

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

Тепер ви можете використовувати створений Blob так, як хочете, у моєму випадку я хочу зберегти його на диску.

3. Необов’язково: збережіть файл на комп'ютері користувача за допомогою FileSaver

Я використовував FileSaver.js для збереження завантаженого файлу на диск, якщо вам це потрібно, скористайтеся цією бібліотекою javascript:

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

Я очікую, що це допоможе іншим з більш конкретними потребами.


1
Об'єктиURL за визначенням локальні. Об'єктні URL-адреси - це URL-адреси, які вказують на файли на диску. Зважаючи на те, що не існує такого поняття, як міждоменний об'єктURL, ви поєднуєте дві різні концепції, таким чином, ваша проблема з використанням даного рішення.
BrianFreud

1
@BrianFreud Я зрозумів, що це не зовсім відповідь на це питання. Але я все ще вважаю, що її гарну відповідь потрібно залишити, оскільки я прийшов сюди, шукаючи відповідь на трохи інше запитання "Як отримати файл або крапку з URL-адреси?". Якщо ви перевіряєте свою власну відповідь, є 10 оновлень на тему "Це не працює у випадку міждоменних запитів. '. Тож понад 10 осіб сюди шукали. Тоді я вирішив залишити його тут.
Вагнер Бертоліні Юніор

Проблема в тому, що ваша відповідь свідомо не відповідає на це запитання. Звичайна URL-адреса та URL-адреса об'єкта - це дві абсолютно різні речі. Що стосується кількості оновлень на тему "Це не працює у випадку міждоменних запитів.", Ви не вважаєте, що краще пояснити, чому це тут буквально неможливо, і вказати на те, що десь показує відповідь на звичайні URL-адреси. чим плутати речі тут, конфулюючи звичайні URL-адреси та об’єктні URL-адреси?
BrianFreud

@BrianFreud не соромтесь запропонувати змінити мою відповідь. Я буду вивчати тему, можливо, я неправильно зрозумів, що таке "objectURL" та "URL-адреса об'єкта" ... Англійська мова не є моєю рідною. Я зроблю дослідження з цього питання, щоб дати кращу відповідь. Але я думаю, що це інші, які приходять сюди, шукаючи чогось іншого. Я не шукав "objectURL", щоб потрапити сюди, це був мій пункт раніше. Але я теж тебе.
Вагнер Бертоліні Юніор

2

Якщо ви все одно показуєте файл на полотні, ви також можете конвертувати вміст полотна в об'єкт 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);
})

2
Зауважте, що це фактично не повертає вам той самий оригінальний файл; це робить новий файл зображення на ходу. Коли я востаннє тестував це пару років тому, я виявив, що принаймні в Chrome новий файл зображення зовсім не стискається - у мене було 10k jpgs, що перетворюється на 2,5 mb jpgs.
BrianFreud
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.