Verwenden der Ajax-Methode von jQuery zum Abrufen von Bildern als Blob

83

Ich habe kürzlich eine andere (verwandte) Frage gestellt, die zu dieser Folgefrage führte: Senden von Daten anstelle einer Datei für ein Eingabeformular

Beim Lesen der Dokumentation zu jQuery.ajax () ( http://api.jquery.com/jQuery.ajax/ ) scheint die Liste der akzeptierten Datentypen keine Bilder zu enthalten.

Ich versuche, ein Bild mit jQuery.get (oder jQuery.ajax, wenn ich muss) abzurufen, dieses Bild in einem Blob zu speichern und es in einer POST-Anfrage auf einen anderen Server hochzuladen. Derzeit sieht es so aus, als ob meine Bilder aufgrund der Nichtübereinstimmung in den Datentypen beschädigt sind (Größe in Byte nicht übereinstimmend usw.).

Der Code, um dies auszuführen, lautet wie folgt (er ist in Coffeescript, sollte aber nicht schwer zu analysieren sein):

handler = (data,status) ->
  fd = new FormData
  fd.append("file", new Blob([data], { "type" : "image/png" }))
  jQuery.ajax {
    url: target_url,
    data: fd,
    processData: false,
    contentType: "multipart/form-data",
    type: "POST",
    complete: (xhr,status) ->
      console.log xhr.status
      console.log xhr.statusCode
      console.log xhr.responseText

  }
jQuery.get(image_source_url, null, handler)

Wie kann ich dieses Bild stattdessen als Blob abrufen?

Jabalsad
quelle
Ich denke, Sie müssen den Antworttyp auf der Serverseite ändern.
Eric Frick
Ich versuche, ein Bild von einer beliebigen URL abzurufen, nicht von einem Server, den ich unbedingt besitze.
Jabalsad
Werfen
Eric Frick
Es scheint, als ob die drei Lösungen in dieser Antwort darin bestehen, entweder (1) das <img> -Tag zu verwenden, (2) den Server dazu zu bringen, die Bilder als byte64-codiert bereitzustellen, oder (3) den Cache des Browsers zu verwenden. (2) ist ausgeschlossen, da ich möchte, dass das Skript mit jeder Bild-URL funktioniert. Ich bin mir nicht sicher, wie ich (1) oder (3) verwenden soll, da ich das Bild nach dem Herunterladen in einen Blob konvertieren muss.
Jabalsad
Option 3 würde nur funktionieren, wenn Sie das Bild bereits heruntergeladen haben. Zum ersten Mal brauchen Sie etwas anderes. Vielleicht 1 wählen?
Eric Frick

Antworten:

145

Sie können dies nicht mit jQuery ajax tun, sondern mit nativem XMLHttpRequest.

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    if (this.readyState == 4 && this.status == 200){
        //this.response is what you're looking for
        handler(this.response);
        console.log(this.response, typeof this.response);
        var img = document.getElementById('img');
        var url = window.URL || window.webkitURL;
        img.src = url.createObjectURL(this.response);
    }
}
xhr.open('GET', 'http://jsfiddle.net/img/logo.png');
xhr.responseType = 'blob';
xhr.send();      

BEARBEITEN

Wenn Sie dieses Thema noch einmal aufgreifen, scheint es tatsächlich möglich zu sein, dies mit jQuery 3 zu tun

jQuery.ajax({
        url:'https://images.unsplash.com/photo-1465101108990-e5eac17cf76d?ixlib=rb-0.3.5&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ%3D%3D&s=471ae675a6140db97fea32b55781479e',
        cache:false,
        xhr:function(){// Seems like the only way to get access to the xhr object
            var xhr = new XMLHttpRequest();
            xhr.responseType= 'blob'
            return xhr;
        },
        success: function(data){
            var img = document.getElementById('img');
            var url = window.URL || window.webkitURL;
            img.src = url.createObjectURL(data);
        },
        error:function(){
            
        }
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<img id="img" width=100%>

oder

Verwenden Sie xhrFields, um den responseType festzulegen

    jQuery.ajax({
            url:'https://images.unsplash.com/photo-1465101108990-e5eac17cf76d?ixlib=rb-0.3.5&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ%3D%3D&s=471ae675a6140db97fea32b55781479e',
            cache:false,
            xhrFields:{
                responseType: 'blob'
            },
            success: function(data){
                var img = document.getElementById('img');
                var url = window.URL || window.webkitURL;
                img.src = url.createObjectURL(data);
            },
            error:function(){
                
            }
        });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
    <img id="img" width=100%>

Musa
quelle
Vielen Dank. Ich habe es gerade herausgefunden und deine Antwort gesehen. Es ist ähnlich wie bei mir (abgesehen von der Tatsache, dass ich es in einem Formular poste, anstatt es auf ein <img> -Objekt zu setzen). Ich werde es trotzdem als richtig markieren :)
Jabalsad
@jabalsad die gestellte Frage How can I retrieve this image as a blob instead?, jedenfalls, die nur zur Demo diente, handlerwird sie nehmen this.responseund zu einem Formdata-Objekt hinzufügen und über Ajax senden.
Musa
2
+1, funktioniert super! Und zu
Ihrer Information
9
2017: jQuery kann immer noch nicht mit dem Typ 'blob' umgehen?
Robsch
1
'xhrFields' funktioniert auch in jQuery 2 (getestet in 2.2.4)
Bampfer
15

Wenn Sie Fehlermeldungen mit jQuery.AJAX behandeln müssen, müssen Sie die xhrFunktion so ändern , dass sie im responseTypeFehlerfall nicht geändert wird.

Sie müssen das responseType" Blob " also nur ändern , wenn es sich um einen erfolgreichen Aufruf handelt:

$.ajax({
    ...
    xhr: function() {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 2) {
                if (xhr.status == 200) {
                    xhr.responseType = "blob";
                } else {
                    xhr.responseType = "text";
                }
            }
        };
        return xhr;
    },
    ...
    error: function(xhr, textStatus, errorThrown) {
        // Here you are able now to access to the property "responseText"
        // as you have the type set to "text" instead of "blob".
        console.error(xhr.responseText);
    },
    success: function(data) {
        console.log(data); // Here is "blob" type
    }
});

Hinweis

Wenn Sie debuggen und einen Haltepunkt an der Stelle direkt nach dem Setzen xhr.responseTypevon " blob " platzieren, können Sie feststellen, dass beim Versuch, den Wert für zu responseTexterhalten, die folgende Meldung angezeigt wird:

Auf den Wert kann nur zugegriffen werden, wenn der 'responseType' des Objekts '' oder 'text' ist (war 'blob').

Alberto
quelle
1
Vielen Dank! Dies war die Lösung, nach der ich gesucht habe. Ich brauchte AJAX, um die erfolgreiche Antwort als "Blob" (in meinem Fall ZIP-Archiv) in der .done()Methode zu behandeln, und wenn etwas schief ging, sollte die Antwort in der .fail()Methode als "Text" behandelt werden, da die Antwort sonst responseTextleer war usw. Dies Lösung hat perfekt für mich funktioniert!
informatik01
4

Ein großes Dankeschön an @Musa und hier ist eine nette Funktion, die die Daten in eine Base64-Zeichenfolge konvertiert. Dies kann nützlich sein, wenn Sie eine Binärdatei (pdf, png, jpeg, docx, ...) in einer WebView verarbeiten, die die Binärdatei abruft. Sie müssen jedoch die Daten der Datei sicher in Ihre App übertragen.

// runs a get/post on url with post variables, where:
// url ... your url
// post ... {'key1':'value1', 'key2':'value2', ...}
//          set to null if you need a GET instead of POST req
// done ... function(t) called when request returns
function getFile(url, post, done)
{
   var postEnc, method;
   if (post == null)
   {
      postEnc = '';
      method = 'GET';
   }
   else
   {
      method = 'POST';
      postEnc = new FormData();
      for(var i in post)
         postEnc.append(i, post[i]);
   }
   var xhr = new XMLHttpRequest();
   xhr.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200)
      {
         var res = this.response;
         var reader = new window.FileReader();
         reader.readAsDataURL(res); 
         reader.onloadend = function() { done(reader.result.split('base64,')[1]); }
      }
   }
   xhr.open(method, url);
   xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
   xhr.send('fname=Henry&lname=Ford');
   xhr.responseType = 'blob';
   xhr.send(postEnc);
}
mxl
quelle