Пустые файлы, загруженные в Android. Исходный браузер.

Я создаю веб-сайт для мобильных телефонов, который изменяет размер фотографий и загружает их.

$('#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); }); 

Это работает в Chrome для Android и в Safari на iOS, но в родном Android-браузере файлы имеют длину содержимого 0 и имя Blob + UID. Когда файл добавляется в formdata, размер также кажется довольно большим (900 К против 50 тыс. В Chrome).

Функция 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; } 

Есть ли способ заставить это работать в родном Android-браузере?

Solutions Collecting From Web of "Пустые файлы, загруженные в Android. Исходный браузер."

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

В конце концов я достиг решения, которое почти полностью прозрачно. Подход состоял в том, чтобы полировать сломанную FormData с помощью blob, который добавляет данные в необходимый формат для multipart/form-data . Он отменяет send() XHR send() с версией, которая считывает blob в буфер, который отправляется в запросе.

Вот основной код:

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

И просто используйте его так, вызывая fd.append(name, value) как обычно после:

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

Как насчет того, чтобы нарисовать его на холсте, используя матрицу, чтобы масштабировать ее до canvas.toDataURL размера, а затем отправить ее на сервер с помощью canvas.toDataURL . Проверьте этот вопрос .

Я использую это, чтобы исправить проблему:

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