您的位置:首页 > 其它

如何在移动web上上传文件..

2016-04-13 00:00 92 查看
xmlhttprequest2.0 可以支持文件上传.这东东很方便,但是在实际使用中碰到了一些问题.这里记录下.

正常情况下我们是这样生成2进制文件的.

//data为文件的base64编码
function dataURLtoBlob(data) {
var tmp = data.split(',');

tmp[1] = tmp[1].replace(//s/g,'');
var binary = atob(tmp[1]);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
}

但是在android手机上可能会由于没有blob对象导致无法生成blob.怎么办捏.可以使用以下代码:

function newBlob(data, datatype){
var out;
try {
out = new Blob([data], {type: datatype});
//一切正常,直接使用blob.
} catch (e) {
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;

if (e.name == 'TypeError' && window.BlobBuilder) {
var bb = new BlobBuilder();
bb.append(data.buffer);
out = bb.getBlob(datatype);
//还可以抢救一下..使用blobbuilder来生成文件..
} else {
//没救了,放弃治疗.
}
}
return out;
}

ok.现在文件已经ready了.

我们创建一个formadata

var file = dataURLtoBlob(img);
fd.append('img',file);

愉快的上传….然后…然后…没有然后了…抓包看下.

------WebKitFormBoundarysToAVAYMLPFfJF96
Content-Disposition: form-data; name="img"; filename="blob"
Content-Type: application/octet-stream ------WebKitFormBoundarysToAVAYMLPFfJF96--

文件的内容呢…

好吧..既然没法愉快用formdata..那么就自己动手生成一个post的包体吧…下面是相关的代码..

function FormDataShim () {
var o = this,
parts = [],// Data to be sent
boundary = Array(5).join('-') + (+new Date() * (1e16*Math.random())).toString(32),
oldSend = XMLHttpRequest.prototype.send;

this.append = function (name, value, filename) {
parts.push('--' + boundary + '/r/nContent-Disposition: form-data; name="' + name + '"');

if (value instanceof Blob) {
parts.push('; filename="'+ (filename || 'blob') +'"/r/nContent-Type: ' + value.type + '/r/n/r/n');
parts.push(value);
} else {
parts.push('/r/n/r/n' + value);
}
parts.push('/r/n');
};

//把xhr的send方法重写一下.
XMLHttpRequest.prototype.send = function (val) {
var fr,
data,
oXHR = this;

if (val === o) {
// 最后加一下boundary..注意这里一定要在最后加/r/n..否则服务器有可能会解析参数失败..
parts.push('--' + boundary + '--/r/n');

data = new XBlob(parts);
fr = new FileReader();
fr.onload = function () { oldSend.call(oXHR, fr.result); };
fr.onerror = function (err) { throw err; };
fr.readAsArrayBuffer(data);

// 设置content-type
this.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
XMLHttpRequest.prototype.send = oldSend;
}
else {
oldSend.call(this, val);
}
};
}

最后完整的代码长这样

function newBlob(data, datatype){
var out;
try {
out = new Blob([data], {type: datatype});
}
catch (e) {
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;

if (e.name == 'TypeError' && window.BlobBuilder) {
var bb = new BlobBuilder();
bb.append(data.buffer);
out = bb.getBlob(datatype);
}
else if (e.name == "InvalidStateError") {
out = new Blob([data], {type: datatype});
}
else {
}
}
return out;
}

// 判断是否需要blobbuilder
var 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;
})(),
blobConstruct = !!(function () {
try { return new Blob(); } catch (e) {}
})(),
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 () {
// Store a reference to this
var o = this,
parts = [],// Data to be sent
boundary = Array(5).join('-') + (+new Date() * (1e16*Math.random())).toString(32),
oldSend = XMLHttpRequest.prototype.send;

this.append = function (name, value, filename) {
parts.push('--' + boundary + '\r\nContent-Disposition: form-data; name="' + name + '"');

if (value instanceof Blob) {
parts.push('; filename="'+ (filename || 'blob') +'"\r\nContent-Type: ' + value.type + '\r\n\r\n');
parts.push(value);
} else {
parts.push('\r\n\r\n' + value);
}
parts.push('\r\n');
};

// Override XHR send()
XMLHttpRequest.prototype.send = function (val) {
var fr,
data,
oXHR = this;

if (val === o) {
//注意不能漏最后的\r\n ,否则有可能服务器解析不到参数.
parts.push('--' + boundary + '--\r\n');
data = new XBlob(parts);
fr = new FileReader();
fr.onload = function () { oldSend.call(oXHR, fr.result); };
fr.onerror = function (err) { throw err; };
fr.readAsArrayBuffer(data);

this.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
XMLHttpRequest.prototype.send = oldSend;
}
else {
oldSend.call(this, val);
}
};
}

//把图片转成formdata 可以使用的数据...
//这里要把\s替换掉..要不然atob的时候会出错....
function dataURLtoBlob(data) {
var tmp = data.split(',');

tmp[1] = tmp[1].replace(/\s/g,'');
var binary = atob(tmp[1]);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new newBlob(new Uint8Array(array), 'image/jpeg');
}

function uploadFile(img){
var fd = needsFormDataShim ? new FormDataShim() : new FormData();
var file = dataURLtoBlob(img);
fd.append('img',file);

var prog = function(e){
/*你的逻辑*/
}
var load = function(e){
/*你的逻辑*/
}
var error = function(e){
/*你的逻辑*/
}
var abort = function(e){
/*你的逻辑*/
}

var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress',prog,false);
xhr.addEventListener('load',load,false);
xhr.addEventListener('error',error,false);
xhr.addEventListener('abort',abort,false);

xhr.onreadystatechange = function(){
/*你的逻辑*/
}
xhr.open('POST','/upload',true);
xhr.send(fd);
}



我的代码

document.addEventListener('DOMContentLoaded', init, false);

function init() {
var u = new UploadPic();
u.init({
input: document.querySelector('#selectFile')
});
}

function UploadPic() {
this.sw = 0;
this.sh = 0;
this.tw = 0;
this.th = 0;
this.scale = 0;
this.maxSize = 0;
this.fileSize = 0;
this.fileDate = null;
this.fileType = '';
this.fileName = '';
this.input = null;
this.canvas = null;
this.mime = {};
this.type = '';
this.callback = function () {
};
this.loading = function () {
};
}

UploadPic.prototype.init = function (options) {
this.input = options.input;
this.mime = {'png': 'image/png', 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'bmp': 'image/bmp'};
this.callback = options.callback || function () {
};
this._addEvent();
};

UploadPic.prototype._addEvent = function () {
var _this = this;

function tmpSelectFile(ev) {
_this._handelSelectFile(ev);
}

this.input.addEventListener('change', tmpSelectFile, false);
};

UploadPic.prototype._handelSelectFile = function (ev) {
var file = ev.target.files[0];

this.type = file.type;

// 如果没有文件类型,则通过后缀名判断(解决微信及360浏览器无法获取图片类型问题)
if (!this.type) {
this.type = this.mime[file.name.match(/\.([^\.]+)$/i)[1]];
}

if (!/image.(png|jpg|jpeg|bmp)/.test(this.type)) {
alert('选择的文件类型不是图片');
return;
}

if (file.size > this.maxSize) {
alert('选择文件大于' + this.maxSize / 1024 / 1024 + 'M,请重新选择');
return;
}

this.fileName = file.name;
this.fileSize = file.size;
this.fileType = this.type;
this.fileDate = file.lastModifiedDate;

this._readImage(file);
};

UploadPic.prototype._readImage = function (file) {
var _this = this;
this._getURI(file, this.callback);
};

UploadPic.prototype._getURI = function (file, callback) {
var reader = new FileReader();
var _this = this;

function tmpLoad() {
// 头不带图片格式,需填写格式
var re = /^data:base64,/;
var ret = this.result + '';

if (re.test(ret)) ret = ret.replace(re, 'data:' + _this.mime[_this.fileType] + ';base64,');

callback && callback(ret);
}

reader.onload = tmpLoad;

reader.readAsDataURL(file);

return false;
};

转载:

http://stackoverflow.com/questions/15639070/empty-files-uploaded-in-android-native-browser/28809955#28809955

http://hao.jser.com/archive/7247/

http://www.haomou.net/2016/01/14/2016_android_blob/

http://www.oschina.net/question/2502182_2139420
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: