Fichiers vides téléchargés dans le navigateur natif Android

Je crée un site Web pour les téléphones mobiles qui redimensionne les photos et les télécharge.

$('#ImgPreview canvas').each(function(pIndex) { vFormData.append(pIndex, canvasToJpegBlob($(this)[0]), vIssueId +'-attachment0'+ pIndex +'.jpg'); }); $.ajax({ url: '/api/ob/issuefileupload', data: vFormData, processData: false, contentType: false, type: 'POST' }).done(function(pData) { window.location = '/issue?id='+ vIssueId; }).fail(function(pJqXHR) { alert(My.Strings.UploadFailed); }); 

Cela fonctionne dans Chrome pour Android et dans Safari sur iOS, mais dans le navigateur natif Android, les fichiers ont une longueur de contenu de 0 et nomment Blob + UID. Lorsque le fichier est ajouté aux formdata, la taille semble également assez grande (900k opposée à 50k dans Chrome).

La fonction canvasToJpegBlob:

 function canvasToJpegBlob(pCanvas) { var vMimeType = "image/jpeg", vDataURI, vByteString, vBlob, vArrayBuffer, vUint8Array, i, vBlobBuilder; vDataURI = pCanvas.toDataURL(vMimeType, 0.8); vByteString = atob(vDataURI.split(',')[1]); vArrayBuffer = new ArrayBuffer(vByteString.length); vUint8Array = new Uint8Array(vArrayBuffer); for (i = 0; i < vByteString.length; i++) { vUint8Array[i] = vByteString.charCodeAt(i); } try { vBlob = new Blob([vUint8Array.buffer], {type : vMimeType}); } catch(e) { window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; if (e.name === 'TypeError' && window.BlobBuilder) { vBlobBuilder = new BlobBuilder(); vBlobBuilder.append(vUint8Array.buffer); vBlob = vBlobBuilder.getBlob(vMimeType); } else if (e.name === 'InvalidStateError') { vBlob = new Blob([vUint8Array.buffer], {type : vMimeType}); } else { alert(My.Strings.UnsupportedFile); } } return vBlob; } 

Existe-t-il un moyen d'utiliser cette fonctionnalité dans le navigateur natif de Android?

J'ai également rencontré ce problème et je devais trouver une solution plus générique, car dans certains cas, je n'aurai pas le contrôle sur le code côté serveur.

Finalement, j'ai atteint une solution presque complètement transparente. L'approche était de rendre polyvalent le FormData cassé avec un blob qui ajoute des données au format nécessaire pour les données multipart/form-data . Il remplace l' send() de XHR send() par une version qui lit le blob dans un tampon qui est envoyé dans la requête.

Voici le code principal:

 var // Android native browser uploads blobs as 0 bytes, so we need a test for that needsFormDataShim = (function () { var bCheck = ~navigator.userAgent.indexOf('Android') && ~navigator.vendor.indexOf('Google') && !~navigator.userAgent.indexOf('Chrome'); return bCheck && navigator.userAgent.match(/AppleWebKit\/(\d+)/).pop() <= 534; })(), // Test for constructing of blobs using new Blob() blobConstruct = !!(function () { try { return new Blob(); } catch (e) {} })(), // Fallback to BlobBuilder (deprecated) XBlob = blobConstruct ? window.Blob : function (parts, opts) { var bb = new (window.BlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder); parts.forEach(function (p) { bb.append(p); }); return bb.getBlob(opts ? opts.type : undefined); }; function FormDataShim () { var // Store a reference to this o = this, // Data to be sent parts = [], // Boundary parameter for separating the multipart values boundary = Array(21).join('-') + (+new Date() * (1e16*Math.random())).toString(36), // Store the current XHR send method so we can safely override it oldSend = XMLHttpRequest.prototype.send; this.append = function (name, value, filename) { parts.push('--' + boundary + '\nContent-Disposition: form-data; name="' + name + '"'); if (value instanceof Blob) { parts.push('; filename="'+ (filename || 'blob') +'"\nContent-Type: ' + value.type + '\n\n'); parts.push(value); } else { parts.push('\n\n' + value); } parts.push('\n'); }; // Override XHR send() XMLHttpRequest.prototype.send = function (val) { var fr, data, oXHR = this; if (val === o) { // Append the final boundary string parts.push('--' + boundary + '--'); // Create the blob data = new XBlob(parts); // Set up and read the blob into an array to be sent fr = new FileReader(); fr.onload = function () { oldSend.call(oXHR, fr.result); }; fr.onerror = function (err) { throw err; }; fr.readAsArrayBuffer(data); // Set the multipart content type and boudary this.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary); XMLHttpRequest.prototype.send = oldSend; } else { oldSend.call(this, val); } }; } 

Et il suffit de l'utiliser comme tel, en appelant fd.append(name, value) comme fd.append(name, value) normalement après:

 var fd = needsFormDataShim ? new FormDataShim() : new FormData(); 

Que diriez-vous d'essayer de le dessiner sur une toile, en utilisant une matrice pour l' canvas.toDataURL à la taille souhaitée, puis l'envoyer au serveur à l'aide de canvas.toDataURL . Découvrez cette question .

J'utilise ceci pour corriger le problème:

 // not use blob, simply use key value var form = new FormData(); // get you content type and raw data from data url form.append( 'content_type', type); form.append( 'content', raw);