Как получить файл или BLOB-объект из URL-адреса объекта?


127

Я разрешаю пользователю загружать изображения на страницу с помощью перетаскивания и других методов. Когда изображение отбрасывается, я использую его URL.createObjectURLдля преобразования в URL-адрес объекта для отображения изображения. Я не аннулирую URL-адрес, так как я его повторно использую.

Итак, когда придет время создать FormDataобъект, чтобы я мог разрешить им загрузить форму с одним из этих изображений в нем, есть ли какой-нибудь способ вернуть этот URL-адрес объекта обратно в Blobили Fileоколо того, я могу затем добавить его в FormDataобъект?


не забывайте о двух предыдущих комментариях - все, что вам нужно сделать, это отправить XMLHttpRequestна URL-адрес большого двоичного объекта.
gengkev 09

2
Почему бы просто не сохранить где-нибудь исходные файловые объекты, затем использовать URL-адрес объекта для их отображения, а при отправке формы использовать исходные файлы?
user764754

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

Ответы:


89

Современное решение:

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

URL-адрес может быть URL-адресом объекта или обычным URL-адресом.


3
Ницца. Рад видеть, что ES5 упрощает подобные вещи.
BrianFreud 06

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

3
К сожалению, это решение не работает в Chrome. Браузеру не удается загрузить этот URL.
waldgeist

Вальджист, вы обернули это в createObjectUrl ()?
Мэтт Флетчер,

73

Как упоминает генгкев в своем комментарии выше, похоже, что лучший / единственный способ сделать это - использовать вызов 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, у Джо есть более простой ответ на основе ES5 ниже.


19
Когда у вас будет objectURL, который не является локальным для текущего домена и области видимости?
BrianFreud

4
Я сделал то же самое, что и выше, но получил 404, не найденный с помощью xhr. в чем дело?
albert yu

Обратите внимание, что некоторые браузеры (прочтите старый IE ...), если вам нужно их обработать, см. Сообщение stackoverflow.com/questions/17657184/…
mraxus

4
@BrianFreud "Когда у вас будет URL-адрес объекта, который не является локальным для текущего домена и области видимости?" В моем случае я пытаюсь дать блобу Amazon S3 другое имя файла, которое в настоящее время является «guid» на S3 без расширения. Итак, в моем случае я использую междоменный вызов.
Wagner Bertolini Junior

6
«URL-адреса объектов - это URL-адреса, которые указывают на файлы на диске». ObjectURL по определению может быть только локальным.
BrianFreud

13

Может быть, кому-то это пригодится при работе с React / Node / Axios. Я использовал это для моей функции загрузки изображений Cloudinary 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)
         }

    })

2
Это работает для междоменных запросов? Видео в Twitter имеют URL-адрес blob. Мне нужно собрать объект blob, на который указывает URL-адрес blob. Я использую fetch 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

Мне удалось использовать этот однострочник, чтобы получить результат с большим двоичным объектом в качестве свойства данных: 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' Надеюсь, это поможет!


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

3

К сожалению, ответ @BrianFreud не соответствует моим потребностям, у меня была немного другая потребность, и я знаю, что это не ответ на вопрос @BrianFreud, но я оставляю его здесь, потому что многие люди пришли сюда с той же потребностью. Мне нужно было что-то вроде «Как получить файл или большой двоичный объект из URL-адреса?», И текущий правильный ответ не соответствует моим потребностям, потому что он не является междоменным.

У меня есть веб-сайт, который использует изображения из хранилища Amazon S3 / Azure, и там я храню объекты с уникальными идентификаторами:

пример: 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
ObjectURL по определению являются локальными. URL-адреса объектов - это URL-адреса, которые указывают на файлы на диске. Учитывая, что не существует такой вещи, как междоменный URL-адрес объекта, вы объединяете две разные концепции, поэтому ваша проблема использует данное решение.
BrianFreud

1
@BrianFreud Я понял, что это не совсем ответ на этот вопрос. Но я все еще думаю, что это хороший ответ, чтобы оставить его, поскольку я пришел сюда в поисках ответа на немного другой вопрос: «Как получить файл или blob-объект из URL-адреса?». Если вы проверите свой ответ, будет 10 голосов за: «Это не работает в случае междоменных запросов». ». Так что более 10 человек пришли сюда в поисках этого. Тогда я решил оставить его здесь.
Wagner Bertolini Junior

Проблема в том, что ваш ответ сознательно не отвечает на этот вопрос. Обычный URL-адрес и URL-адрес объекта - это две совершенно разные вещи. Что касается количества голосов за «Это не работает в случае междоменных запросов». Не могли бы вы подумать, что лучше объяснить, почему это буквально невозможно здесь, и указать на то место, где действительно отображается ответ для обычных URL-адресов. чем запутать здесь, объединяя обычные URL-адреса и URL-адреса объектов?
BrianFreud

@BrianFreud не стесняйтесь предлагать отредактировать мой ответ. Я буду изучать эту тему, может быть, я неправильно понял, что такое «objectURL» против «object URL» ... Английский не мой родной. Я проведу исследование по этому поводу, чтобы дать лучший ответ. Но я думаю, что это другие, которые приходят сюда в поисках чего-то другого. Я не искал "objectURL", чтобы попасть сюда, это было моей точкой зрения раньше. Но я тоже тебя достал.
Wagner Bertolini Junior

2

Если вы все равно показываете файл на холсте, вы также можете преобразовать его содержимое в большой двоичный объект.

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, превращающихся в jpgs размером 2,5 МБ.
BrianFreud
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.