关于安卓手机微信浏览器中使用XMLHttpRequest 2上传图片显示字节数为0的解决办法


Posted in Javascript onMay 17, 2016

 前端JS中使用XMLHttpRequest 2上传图片到服务器,PC端和大部分手机上都正常,但在少部分安卓手机上上传失败,服务器上查看图片,显示字节数为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事件显示数据发送进度
xhr.upload.addEventListener('progress', function (e) {
pecent = ~~(100 * e.loaded / e.total) / 2;
// 利用pecent来显示上传进度
}, 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来实现表单数据提交。FormData是一种针对XHR2设计的新型数据类型,使用它我们可以很方便地实时以JavaScript创建HTML <Form>,然后通过AJAX提交该表单。在上述代码中,提交的表单中的字段名为imagefile,值是blob,这是一个通过getBlob函数构造并返回的文件Blob。通过该方法上传文件简单直观。

然后我们在服务端接收并保存图片,并返回已上传的图片的信息。

下面是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这个包来接收上传文件的数据,然后将文件保存到/public/uploadImgs/dealInfo目录下(假定已在express中将public设置为static的根目录),并将图片按照指定的规则重命名,以保证上传图片不会因为名称相同而被覆盖。另外,代码中使用Q来避免直接使用回调函数,以更好地对函数功能进行分离。

上面的代码在PC端浏览器以及大部分主流移动设备上都能正常工作,但是少部分Android设备上却会出现上传的图片字节数为0的情况。具体的原因大家可以看下面几个网页中的描述:

就是说这个是Android的一个bug!

那如何解决呢?

其实从上面给出的页面中可以找到答案,就是我们得换一种文件上传方式。在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事件显示数据发送进度
xhr.upload.addEventListener('progress', function (e) {
pecent = ~~(100 * e.loaded / e.total) / 2;
// 利用pecent来显示上传进度
}, false);
xhr.send(buffer.buffer); // 以ArrayBuffer的方式上传图片
}

我将有变化的地方加了高亮显示。以ArrayBuffer方式上传图片必须添加'application/octet-stream'的RequestHeader,否则服务器无法响应请求。另外,通过这种方式上传图片我们也无法从表单数据中获取到文件类型,可以将文件类型以query的方式传到服务器,然后服务器根据文件类型来生成对应的文件,以下是经过少量修改之后的服务器代码:

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手机,包括微信浏览器。注意不是所有的Android手机都会存在该问题,如果你发现在Andriod手机上无法上传图片,尤其是在微信浏览器中,则可以尝试下上面的方法。

以上所述是小编给大家介绍的关于安卓手机微信浏览器中使用XMLHttpRequest 2上传图片显示字节数为0的解决办法,希望对大家有所帮助!

Javascript 相关文章推荐
innerText和innerHTML 一些问题分析
May 18 Javascript
javascript css styleFloat和cssFloat
Mar 15 Javascript
为什么JS中eval处理JSON数据要加括号
Apr 13 Javascript
javascript委托(Delegate)blur和focus用法实例分析
May 26 Javascript
jQuery简单实现验证邮箱格式
Jul 15 Javascript
使用javascript插入样式
Mar 14 Javascript
javascript事件模型介绍
May 31 Javascript
js实现统计字符串中特定字符出现个数的方法
Aug 02 Javascript
基于js中this和event 的区别(详解)
Oct 24 Javascript
使用vue-route 的 beforeEach 实现导航守卫(路由跳转前验证登录)功能
Mar 22 Javascript
jQuery实现当拉动滚动条到底部加载数据的方法分析
Jan 24 jQuery
解决vue 使用setTimeout,离开当前路由setTimeout未销毁的问题
Jul 21 Javascript
Web前端新人笔记之jquery入门心得(新手必看)
May 17 #Javascript
Angularjs中的事件广播 —全面解析$broadcast,$emit,$on
May 17 #Javascript
iScroll.js 使用方法参考
May 16 #Javascript
BootStrap的JS插件之轮播效果案例详解
May 16 #Javascript
老司机带你解读jQuery插件开发流程
May 16 #Javascript
jQuery 获取多选框的值及多选框中文的函数
May 16 #Javascript
jQuery插件制作的实例教程
May 16 #Javascript
You might like
模拟OICQ的实现思路和核心程序(一)
2006/10/09 PHP
用PHP实现维护文件代码
2007/06/14 PHP
PHP统计目录下的文件总数及代码行数(去除注释及空行)
2011/01/17 PHP
linux下为php添加curl扩展的方法
2011/07/29 PHP
PHP中如何定义和使用常量
2013/02/28 PHP
php调用google接口生成二维码示例
2014/04/28 PHP
最新制作ThinkPHP3.2.3完全开发手册
2015/11/23 PHP
基于php编程规范(详解)
2017/08/17 PHP
php提供实现反射的方法和实例代码
2019/09/17 PHP
PHP 裁剪图片
2021/03/09 PHP
javascript prototype,executing,context,closure
2008/12/24 Javascript
Prototype 学习 工具函数学习($A方法)
2009/07/12 Javascript
js实现倒计时(距离结束还有)示例代码
2013/07/24 Javascript
iframe的父子窗口之间的对象相互调用基本用法
2013/09/03 Javascript
js弹出层永远居中实现思路及代码
2013/11/29 Javascript
基于JavaScript实现Json数据根据某个字段进行排序
2015/11/24 Javascript
JavaScript如何实现图片懒加载(lazyload) 提高用户体验(增强版)
2016/11/30 Javascript
详解Vue自定义过滤器的实现
2017/01/10 Javascript
vue.js利用Object.defineProperty实现双向绑定
2017/03/09 Javascript
js拖动滑块和点击水波纹效果实例代码
2018/10/16 Javascript
Vue递归实现树形菜单方法实例
2018/11/06 Javascript
小程序封装wx.request请求并创建接口管理文件的实现
2019/04/29 Javascript
JavaScript中的 new 命令
2019/05/22 Javascript
JS中getElementsByClassName与classList兼容性问题解决方案分析
2019/08/07 Javascript
重命名批处理python脚本
2013/04/05 Python
用Python写冒泡排序代码
2016/04/12 Python
python利用MethodType绑定方法到类示例代码
2017/08/27 Python
Python中整数的缓存机制讲解
2019/02/16 Python
Python 中包/模块的 `import` 操作代码
2019/04/22 Python
python+selenium 鼠标事件操作方法
2019/08/24 Python
CSS3绘制有活力的链接下划线
2016/07/14 HTML / CSS
市场营销专业毕业生自荐信
2013/11/02 职场文书
陕西导游词
2015/02/04 职场文书
爱心捐书倡议书
2015/04/27 职场文书
Nginx如何配置Http、Https、WS、WSS的方法步骤
2021/05/11 Servers
解决pycharm安装scrapy DLL load failed:找不到指定的程序的问题
2021/06/08 Python