96 votes

Utilisation de la méthode ajax de jQuery pour récupérer des images sous forme de blob

J'ai récemment posé une autre question (connexe), qui a conduit à cette question complémentaire : Soumettre des données au lieu d'un fichier pour un formulaire de saisie

En lisant la documentation de jQuery.ajax() ( http://api.jquery.com/jQuery.ajax/ ), il semble que la liste des types de données acceptés n'inclut pas les images.

J'essaie de récupérer une image à l'aide de jQuery.get (ou de jQuery.ajax si nécessaire), de stocker cette image dans un Blob et de la télécharger sur un autre serveur dans une requête POST. Actuellement, il semble qu'en raison de la non-concordance des types de données, mes images finissent par être corrompues (non-concordance de la taille en octets, etc.).

Le code pour réaliser cette opération est le suivant (il est en coffeescript mais ne devrait pas être difficile à analyser) :

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)

Comment puis-je récupérer cette image en tant que blob à la place ?

175voto

Musa Points 50000

Vous ne pouvez pas faire cela avec jQuery ajax, mais avec XMLHttpRequest natif.

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

EDIT

En réexaminant ce sujet, il semble qu'il soit possible de le faire avec jQuery 3.

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%>

o

utiliser xhrFields pour définir le type de réponse (responseType)

    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%>

29voto

Alberto Points 365

Si vous devez gérer les messages d'erreur en utilisant jQuery.AJAX vous devrez modifier le xhr fonction donc le responseType n'est pas modifié lorsqu'une erreur se produit.

Vous devrez donc modifier le responseType à " blob "seulement s'il s'agit d'un appel réussi :

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

Note

Si vous déboguez et placez un point d'arrêt à l'endroit juste après la définition de l'attribut xhr.responseType à " blob "vous pouvez noter que si vous essayez d'obtenir la valeur de responseText vous obtiendrez le message suivant :

La valeur n'est accessible que si le "responseType" de l'objet est '' ou 'text' (était 'blob').

6voto

mxl Points 97

Un grand merci à @Musa et voici une fonction soignée qui convertit les données en une chaîne de caractères base64. Cela peut s'avérer pratique lorsque vous manipulez un fichier binaire (pdf, png, jpeg, docx, ...) dans une WebView qui reçoit le fichier binaire mais vous devez transférer les données du fichier en toute sécurité dans votre application.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X