About Android phone micro-mail browser using XMLHttpRequest 2 to upload images showing byte number of 0 solution _javascript Tips

Source: Internet
Author: User

The front-end JS uses XMLHttpRequest 2 to upload pictures to the server. The PC and most mobile phones are normal, but uploading fails on a small number of Android phones. Viewing pictures on the server shows 0 bytes. Here is the core code for uploading pictures:
HTML
<input type = "file" id = "choose" capture = "camera" accept = "image / *">
JavaScript
var filechooser = document.getElementById ("choose");
filechooser.onchange = function () {
var _this = $ (this);
if (! this.files.length) return;
var files = Array.prototype.slice.call (this.files);
if (files.length> 1) {
alert ("Only one image can be uploaded at a time");
return;
}
files.forEach (function (file, i) {
if (! / \ / (?: jpeg | png | gif) /i.test (file.type)) return;
var reader = new FileReader ();
reader.onload = function () {
var result = this.result;
upload (result, file.type);
};
reader.readAsDataURL (file);
});
};
function upload (basestr, type) {
var xhr = new XMLHttpRequest ();
var text = window.atob (basestr.split (",") [1]);
var buffer = new Uint8Array (text.length);
var pecent = 0;
for (var i = 0; i <text.length; i ++) {
buffer [i] = text.charCodeAt (i);
}
var blob = getBlob (buffer, type);
var formdata = new FormData ();
formdata.append ('imagefile', blob);
xhr.open ('post', '/ uploadtest');
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var jsonData = JSON.parse (xhr.responseText);
console.log (jsonData);
}
};
// Use the progress event to display the data sending progress
xhr.upload.addEventListener ('progress', function (e) {
pecent = ~~ (100 * e.loaded / e.total) / 2;
// Use pecent to display upload progress
}, false);
xhr.send (formdata);
}
function getBlob (buffer, format) {
var Builder = window.WebKitBlobBuilder || window.MozBlobBuilder;
if (Builder) {
var builder = new Builder ();
builder.append (buffer);
return builder.getBlob (format);
} else {
return new window.Blob ([buffer], {type: format});
}
}
The above code uses FormData to implement form data submission. FormData is a new data type designed for XHR2. Using it, we can easily create HTML <Form> in JavaScript in real time, and then submit the form through AJAX. In the above code, the field in the submitted form is named imagefile, and the value is blob. This is a file blob constructed and returned by the getBlob function. Uploading files through this method is simple and intuitive.
Then we receive and save the picture on the server, and return the information of the uploaded picture.

Here is an example of Node.js code:
var Q = require ('q');
var fs = require ('fs');
var path = require ('path');
var formidable = require ('formidable');
var moment = require ('moment'); var imageUpload = function () {};
imageUpload.prototype.useFormParseCallback = function (req) {
var deferred = Q.defer ();
var form = new formidable.IncomingForm ();
form.parse (req, deferred.makeNodeResolver ());
return deferred.promise;
};
imageUpload.prototype.uploadImageTest = function (req) {
var pathName = 'uploadImgs / dealInfo /';
var uploadPath = path.join (__ dirname, '../../public/', pathName);
return this.useFormParseCallback (req) .then (function (files) {
var file = files [1] .imagefile;
var fileType = files [1] .imagefile.type.split ('/') [1];
var newFileName = 'upload_' + moment (). format ('x') + Math.random (). toString (). substr (2, 10) + '.' + fileType;
var readStream = fs.createReadStream (file.path);
var writeStream = fs.createWriteStream (uploadPath + newFileName);
var deferred = Q.defer ();
readStream.pipe (writeStream);
readStream.on ('end', deferred.makeNodeResolver ());
return deferred.promise.then (function () {
fs.unlinkSync (file.path);
return {
fileName: newFileName,
filePath: '/' + pathName + newFileName,
fileSize: file.size / 1024> 1024? (~~ (10 * file.size / 1024/1024)) / 10 + "MB": ~~ (file.size / 1024) + "KB"
};
});
});
};
module.exports = imageUpload;
We use the formidable package to receive the data of the uploaded file, and then save the file to the / public / uploadImgs / dealInfo directory (assuming that public has been set as the static root directory in express), and rename the picture according to the specified rules To ensure that the uploaded image will not be overwritten because of the same name. In addition, the use of Q in the code to avoid the use of callback functions directly, in order to better separate the function of the function.
The above code can work normally in PC browsers and most mainstream mobile devices, but on a small number of Android devices, the number of bytes of uploaded pictures will be 0. For specific reasons, you can see the descriptions in the following web pages:
Means that this is a bug in Android!
How to solve it?

In fact, we can find the answer from the page given above, that is, we have to change the file upload method. In XHR2, in addition to uploading files by Blob, you can also upload files by ArrayBuffer.

The following is the modified front-end JavaScript code:

var filechooser = document.getElementById ("choose");
filechooser.onchange = function () {
var _this = $ (this);
if (! this.files.length) return;
var files = Array.prototype.slice.call (this.files);
if (files.length> 1) {
alert ("Only one image can be uploaded at a time");
return;
}
files.forEach (function (file, i) {
if (! / \ / (?: jpeg | png | gif) /i.test (file.type)) return;
var reader = new FileReader ();
reader.onload = function () {
var result = this.result;
upload (result, file.type);
};
reader.readAsDataURL (file);
});
};
function upload (basestr, type) {
var xhr = new XMLHttpRequest ();
var text = window.atob (basestr.split (",") [1]);
var buffer = new Uint8Array (text.length);
var pecent = 0;
for (var i = 0; i <text.length; i ++) {
buffer [i] = text.charCodeAt (i);
}
xhr.open ('post', '/ uploadtest? filetype =' + type.split ('/') [1]);
xhr.setRequestHeader ('Content-Type', 'application / octet-stream');
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var jsonData = JSON.parse (xhr.responseText);
console.log (jsonData);
}
};
// Use the progress event to display the data sending progress
xhr.upload.addEventListener ('progress', function (e) {
pecent = ~~ (100 * e.loaded / e.total) / 2;
// Use pecent to display upload progress
}, false);
xhr.send (buffer.buffer); // Upload pictures in ArrayBuffer
}
I highlighted the changes. To upload pictures in ArrayBuffer mode, the RequestHeader of 'application / octet-stream' must be added, otherwise the server cannot respond to the request. In addition, we can't get the file type from the form data by uploading pictures in this way. We can pass the file type to the server in query mode, and then the server generates the corresponding file according to the file type. The following is a small amount of modification Server code:
imageUpload.pro
totype.uploadImageTest = function (req) {
var pathName = 'uploadImgs / dealInfo /';
var uploadPath = path.join (__ dirname, '../../public/', pathName);
return this.useFormParseCallback (req) .then (function (files) {
var file = files [1] .file;
var fileType = req.query.filetype? ('.' + req.query.filetype): '.png';
var newFileName = 'upload_' + moment (). format ('x') + Math.random (). toString (). substr (2, 10) + '.' + fileType;
var readStream = fs.createReadStream (file.path);
var writeStream = fs.createWriteStream (uploadPath + newFileName);
var deferred = Q.defer ();
readStream.pipe (writeStream);
readStream.on ('end', deferred.makeNodeResolver ());
return deferred.promise.then (function () {
fs.unlinkSync (file.path);
return {
fileName: newFileName,
filePath: '/' + pathName + newFileName,
fileSize: file.size / 1024> 1024? (~~ (10 * file.size / 1024/1024)) / 10 + "MB": ~~ (file.size / 1024) + "KB"
};
});
});
};
The revised code can support Android phones, including WeChat browser. Note that not all Android phones will have this problem. If you find that you cannot upload pictures on Android phones, especially in WeChat browsers, you can try the above method.
The above is a solution introduced by the editor to the use of XMLHttpRequest 2 to upload pictures in the Android mobile WeChat browser. The number of bytes displayed is 0. I hope it will be helpful to everyone!


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.