Jak uzyskać plik lub obiekt blob z adresu URL obiektu?

127

Pozwalam użytkownikowi ładować obrazy na stronę za pomocą przeciągania i upuszczania oraz innych metod. Kiedy obraz jest upuszczany, używam go URL.createObjectURLdo konwersji na adres URL obiektu, aby wyświetlić obraz. Nie odwołuję adresu URL, ponieważ używam go ponownie.

Tak więc, kiedy przychodzi czas na utworzenie FormDataobiektu, aby umożliwić im przesłanie formularza z jednym z tych obrazów, czy jest jakiś sposób, aby następnie odwrócić ten adres URL obiektu z powrotem do Bloblub Filetak, abym mógł następnie dołączyć go do FormDataobiekt?

BrianFreud
źródło
nieważne o poprzednich dwóch komentarzach - wystarczy, że wyślesz XMLHttpRequestadres URL obiektu blob.
gengkev
2
Dlaczego po prostu nie przechowywać gdzieś oryginalnych obiektów plików, a następnie użyć adresu URL obiektu, aby je wyświetlić, a podczas przesyłania formularza użyć oryginalnych plików?
user764754
@ user764754, ponieważ próba uzyskania adresu URL pliku przesyłanego przez użytkownika jest wyświetlana jako „C: \ fakepath”
Malcolm Salvador

Odpowiedzi:

88

Nowoczesne rozwiązanie:

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

Adres URL może być adresem URL obiektu lub normalnym adresem URL.


źródło
3
Miły. Cieszę się, że ES5 upraszcza takie rzeczy.
BrianFreud
11
A jeśli chcesz bezpośrednio pobrać plik z obietnicy, możesz wygenerować plik w następujący sposób. let file = await fetch(url).then(r => r.blob()).then(blobFile => new File([blobFile], "fileNameGoesHere", { type: "image/png" })
dbakiu
3
Niestety to rozwiązanie nie działa u mnie w Chrome. Przeglądarka nie może załadować tego adresu URL.
waldgeist
Waldgeist, czy opakowałeś to w createObjectUrl ()?
Matt Fletcher
73

Jak Gengkev wspomina w swoim komentarzu powyżej, wygląda na to, że najlepszym / jedynym sposobem na zrobienie tego jest wywołanie asynchroniczne 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();

Aktualizacja (2018): w sytuacjach, w których można bezpiecznie używać ES5, Joe ma poniżej prostszą odpowiedź opartą na ES5.

BrianFreud
źródło
19
Czy kiedykolwiek zdarzyło Ci się uzyskać adres URL obiektu, który nie jest lokalny dla bieżącej domeny i zakresu?
BrianFreud
4
Zrobiłem to samo co powyżej, ale nie znaleziono 404 z xhr. co się dzieje?
Albert yu
Zwróć uwagę, że niektóre przeglądarki (czytaj starą IE ...), jeśli chcesz sobie z nimi poradzić, zobacz post stackoverflow.com/questions/17657184/ ...
mraxus
4
@BrianFreud "Czy kiedykolwiek miałbyś mieć adres URL obiektu, który nie jest lokalny dla bieżącej domeny i zakresu?" W moim przypadku próbuję nadać blobowi Amazon S3 inną nazwę pliku, czyli obecnie „guid” na S3 bez rozszerzenia. Tak więc w moim przypadku używam połączenia między domenami.
Wagner Bertolini Junior
6
„Adresy URL obiektów to adresy URL wskazujące pliki na dysku”. ObjectURL z definicji mogą być tylko lokalne.
BrianFreud
12

Może ktoś uzna to za przydatne podczas pracy z React / Node / Axios. Użyłem tego do mojej funkcji przesyłania obrazu Cloudinary react-dropzonew interfejsie użytkownika.

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

    })
spedia
źródło
1
Czy to działa w przypadku żądań między domenami? Filmy na Twitterze mają adres URL obiektu BLOB. Muszę być w stanie zebrać obiekt blob, na który wskazuje adres URL obiektu BLOB. Używam api pobierania w przeglądarce, co powoduje wyświetlenie tego błędu - Refused to connect to 'blob:https://twitter.com/9e00aec3-6729-42fb-b5a7-01f50be302fa' because it violates the following Content Security Policy directive: "connect-src . Czy możesz mieć wskazówkę, co mogę robić źle, a czego nie robić?
gdadsriver
Udało mi się użyć tej jednej linijki, aby uzyskać wynik z blobem jako właściwością danych: const result = await axios.get (url, {responseType: "blob"});
Noah Stahl
4

Na przykład używając fetch, jak poniżej:

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

Możesz wkleić na konsoli Chrome, aby przetestować. plik do pobrania z „sample.xlsx” Mam nadzieję, że może pomóc!

user3843418
źródło
Myślę, że OP zapytał o konwersję adresu URL obiektu BLOB na rzeczywisty plik / obiekt BLOB, a nie na odwrót.
Abhishek Ghosh
3

Niestety odpowiedź @ BrianFreud nie pasuje do moich potrzeb, miałem trochę inną potrzebę i wiem, że to nie jest odpowiedź na pytanie @ BrianFreud, ale zostawiam ją tutaj, ponieważ wiele osób przybyło tutaj z tą samą potrzebą. Potrzebowałem czegoś w stylu „Jak uzyskać plik lub obiekt blob z adresu URL?”, A aktualna poprawna odpowiedź nie odpowiada moim potrzebom, ponieważ nie jest międzydomenowa.

Mam witrynę internetową, która zużywa obrazy z magazynu Amazon S3 / Azure i tam przechowuję obiekty o nazwach z unikatowymi identyfikatorami:

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

Niektóre z tych obrazów należy pobrać z naszego interfejsu systemowego. Aby uniknąć przekazywania tego ruchu przez mój serwer HTTP, ponieważ te obiekty nie wymagają dostępu do żadnych zabezpieczeń (z wyjątkiem filtrowania domeny), postanowiłem wykonać bezpośrednie żądanie w przeglądarce użytkownika i użyć lokalnego przetwarzania, aby nadać plikowi prawdziwą nazwę i rozbudowa.

Aby to osiągnąć, wykorzystałem ten wspaniały artykuł Henry'ego Algusa: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/

1. Pierwszy krok: dodaj obsługę binarną do 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. Krok drugi: Złóż wniosek przy użyciu tego typu transportu.

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

Teraz możesz użyć utworzonego Bloba, jak chcesz, w moim przypadku chcę go zapisać na dysku.

3. Opcjonalnie: Zapisz plik na komputerze użytkownika za pomocą programu FileSaver

Użyłem FileSaver.js do zapisania na dysku pobranego pliku, jeśli chcesz to zrobić, użyj tej biblioteki javascript:

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

Oczekuję, że pomoże to innym z bardziej konkretnymi potrzebami.

Wagner Bertolini Junior
źródło
1
Adresy URL obiektów są z definicji lokalne. Adresy URL obiektów to adresy URL wskazujące pliki na dysku. Biorąc pod uwagę, że nie ma czegoś takiego jak cross-domain objectURL, łączysz dwie różne koncepcje, a tym samym twój problem przy użyciu podanego rozwiązania.
BrianFreud
1
@BrianFreud Rozumiem, że nie jest to do końca odpowiedź na to pytanie. Ale nadal uważam, że to dobra odpowiedź na opuszczenie strony, ponieważ przyszedłem tutaj, szukając odpowiedzi na trochę inne pytanie „Jak pobrać plik lub obiekt blob z adresu URL?”. Jeśli zaznaczysz swoją własną odpowiedź, będzie 10 głosów za „To nie działa w przypadku próśb międzydomenowych. ”. Tak więc przybyło tu ponad 10 osób, które tego szukały. Postanowiłem wtedy zostawić to tutaj.
Wagner Bertolini Junior
Problem w tym, że twoja odpowiedź świadomie nie odpowiada na to pytanie. Zwykły adres URL i adres URL obiektu to dwie zupełnie różne rzeczy. Jeśli chodzi o liczbę głosów za „To nie działa w przypadku żądań między domenami”, czy nie pomyślałbyś, że lepiej wyjaśnić, dlaczego jest to dosłownie niemożliwe w tym miejscu i wskazać miejsce, które pokazuje odpowiedź dla normalnych adresów URL, a raczej niż mylenie rzeczy tutaj, łącząc zwykłe adresy URL i adresy URL obiektów?
BrianFreud,
@BrianFreud zapraszam do zaproponowania zmiany w mojej odpowiedzi. Przestudiuję ten temat, być może źle zrozumiałem, co to jest „objectURL” a „object URL”… Angielski nie jest moim ojczystym. Zrobię badania na ten temat, aby dać lepszą odpowiedź. Ale myślę, że są inni, którzy przyjeżdżają tutaj, szukając czegoś innego. Nie szukałem „objectURL”, aby się tu dostać, to był mój wcześniejszy cel. Ale ciebie też mam.
Wagner Bertolini Junior
2

Jeśli mimo wszystko pokazujesz plik w kanwie, możesz również przekonwertować zawartość kanwy na obiekt 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
źródło
2
Zauważ, że to w rzeczywistości nie daje ci tego samego oryginalnego pliku; tworzy nowy plik obrazu w locie. Kiedy ostatnio testowałem to kilka lat temu, stwierdziłem, że przynajmniej w Chrome nowy plik obrazu nie jest w ogóle skompresowany - miałem 10k jpg zamieniane w 2,5 MB jpg.
BrianFreud