關(guān)于安卓手機(jī)微信瀏覽器中使用XMLHttpRequest 2上傳圖片顯示字節(jié)數(shù)為0的解決辦法
前端JS中使用XMLHttpRequest 2上傳圖片到服務(wù)器,PC端和大部分手機(jī)上都正常,但在少部分安卓手機(jī)上上傳失敗,服務(wù)器上查看圖片,顯示字節(jié)數(shù)為0。下面是上傳圖片的核心代碼:
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("一次只能上傳1張圖片");
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);
}
};
//利用progress事件顯示數(shù)據(jù)發(fā)送進(jìn)度
xhr.upload.addEventListener('progress', function (e) {
pecent = ~~(100 * e.loaded / e.total) / 2;
// 利用pecent來顯示上傳進(jìn)度
}, 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});
}
}
上述代碼使用FormData來實(shí)現(xiàn)表單數(shù)據(jù)提交。FormData是一種針對XHR2設(shè)計(jì)的新型數(shù)據(jù)類型,使用它我們可以很方便地實(shí)時(shí)以JavaScript創(chuàng)建HTML <Form>,然后通過AJAX提交該表單。在上述代碼中,提交的表單中的字段名為imagefile,值是blob,這是一個(gè)通過getBlob函數(shù)構(gòu)造并返回的文件Blob。通過該方法上傳文件簡單直觀。
然后我們在服務(wù)端接收并保存圖片,并返回已上傳的圖片的信息。
下面是Node.js代碼的示例:
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;
我們使用formidable這個(gè)包來接收上傳文件的數(shù)據(jù),然后將文件保存到/public/uploadImgs/dealInfo目錄下(假定已在express中將public設(shè)置為static的根目錄),并將圖片按照指定的規(guī)則重命名,以保證上傳圖片不會(huì)因?yàn)槊Q相同而被覆蓋。另外,代碼中使用Q來避免直接使用回調(diào)函數(shù),以更好地對函數(shù)功能進(jìn)行分離。
上面的代碼在PC端瀏覽器以及大部分主流移動(dòng)設(shè)備上都能正常工作,但是少部分Android設(shè)備上卻會(huì)出現(xiàn)上傳的圖片字節(jié)數(shù)為0的情況。具體的原因大家可以看下面幾個(gè)網(wǎng)頁中的描述:
就是說這個(gè)是Android的一個(gè)bug!
那如何解決呢?
其實(shí)從上面給出的頁面中可以找到答案,就是我們得換一種文件上傳方式。在XHR2中,除了以Blob的方式上傳文件外,還可以ArrayBuffer的方式上傳文件。
下面是修改之后的前端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("一次只能上傳1張圖片");
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);
}
};
//利用progress事件顯示數(shù)據(jù)發(fā)送進(jìn)度
xhr.upload.addEventListener('progress', function (e) {
pecent = ~~(100 * e.loaded / e.total) / 2;
// 利用pecent來顯示上傳進(jìn)度
}, false);
xhr.send(buffer.buffer); // 以ArrayBuffer的方式上傳圖片
}
我將有變化的地方加了高亮顯示。以ArrayBuffer方式上傳圖片必須添加'application/octet-stream'的RequestHeader,否則服務(wù)器無法響應(yīng)請求。另外,通過這種方式上傳圖片我們也無法從表單數(shù)據(jù)中獲取到文件類型,可以將文件類型以query的方式傳到服務(wù)器,然后服務(wù)器根據(jù)文件類型來生成對應(yīng)的文件,以下是經(jīng)過少量修改之后的服務(wù)器代碼:
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].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"
};
});
});
};
修改之后的代碼可以支持Android手機(jī),包括微信瀏覽器。注意不是所有的Android手機(jī)都會(huì)存在該問題,如果你發(fā)現(xiàn)在Andriod手機(jī)上無法上傳圖片,尤其是在微信瀏覽器中,則可以嘗試下上面的方法。
以上所述是小編給大家介紹的關(guān)于安卓手機(jī)微信瀏覽器中使用XMLHttpRequest 2上傳圖片顯示字節(jié)數(shù)為0的解決辦法,希望對大家有所幫助!
相關(guān)文章
JavaScript如何利用Promise控制并發(fā)請求個(gè)數(shù)
大家都知道js是單線程,并不存在真正的并發(fā),但是由于JavaScript的Event Loop機(jī)制,使得異步函數(shù)調(diào)用有了“并發(fā)”這樣的假象。這篇文章主要給大家介紹了關(guān)于JavaScript如何利用Promise控制并發(fā)請求個(gè)數(shù)的相關(guān)資料,需要的朋友可以參考下2021-05-05
淺談layui使用模板引擎動(dòng)態(tài)渲染元素要注意的問題
今天小編就為大家分享一篇淺談layui使用模板引擎動(dòng)態(tài)渲染元素要注意的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09
js實(shí)現(xiàn)數(shù)組去重方法及效率對比
本文主要介紹了js實(shí)現(xiàn)數(shù)組去重方法及效率對比。具有很好的參考價(jià)值,下面跟著小編一起來看下吧2017-02-02
Uniapp?實(shí)現(xiàn)全民分銷功能原理解析
這篇文章主要介紹了Uniapp?實(shí)現(xiàn)全民分銷功能,本篇文章主要介紹全民分銷功能實(shí)現(xiàn)原理,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06

