hdjs
Version:
hdjs framework
172 lines (137 loc) • 5.13 kB
JavaScript
/**
* @fileOverview Transport
* @todo 支持chunked传输,优势:
* 可以将大文件分成小块,挨个传输,可以提高大文件成功率,当失败的时候,也只需要重传那小部分,
* 而不需要重头再传一次。另外断点续传也需要用chunked方式。
*/
define([
'../../base',
'./runtime'
], function( Base, Html5Runtime ) {
var noop = Base.noop,
$ = Base.$;
return Html5Runtime.register( 'Transport', {
init: function() {
this._status = 0;
this._response = null;
},
send: function() {
var owner = this.owner,
opts = this.options,
xhr = this._initAjax(),
blob = owner._blob,
server = opts.server,
formData, binary, fr;
if ( opts.sendAsBinary ) {
server += (/\?/.test( server ) ? '&' : '?') +
$.param( owner._formData );
binary = blob.getSource();
} else {
formData = new FormData();
$.each( owner._formData, function( k, v ) {
formData.append( k, v );
});
formData.append( opts.fileVal, blob.getSource(),
opts.filename || owner._formData.name || '' );
}
if ( opts.withCredentials && 'withCredentials' in xhr ) {
xhr.open( opts.method, server, true );
xhr.withCredentials = true;
} else {
xhr.open( opts.method, server );
}
this._setRequestHeader( xhr, opts.headers );
if ( binary ) {
// 强制设置成 content-type 为文件流。
xhr.overrideMimeType &&
xhr.overrideMimeType('application/octet-stream');
// android直接发送blob会导致服务端接收到的是空文件。
// bug详情。
// https://code.google.com/p/android/issues/detail?id=39882
// 所以先用fileReader读取出来再通过arraybuffer的方式发送。
if ( Base.os.android ) {
fr = new FileReader();
fr.onload = function() {
xhr.send( this.result );
fr = fr.onload = null;
};
fr.readAsArrayBuffer( binary );
} else {
xhr.send( binary );
}
} else {
xhr.send( formData );
}
},
getResponse: function() {
return this._response;
},
getResponseAsJson: function() {
return this._parseJson( this._response );
},
getStatus: function() {
return this._status;
},
abort: function() {
var xhr = this._xhr;
if ( xhr ) {
xhr.upload.onprogress = noop;
xhr.onreadystatechange = noop;
xhr.abort();
this._xhr = xhr = null;
}
},
destroy: function() {
this.abort();
},
_initAjax: function() {
var me = this,
xhr = new XMLHttpRequest(),
opts = this.options;
if ( opts.withCredentials && !('withCredentials' in xhr) &&
typeof XDomainRequest !== 'undefined' ) {
xhr = new XDomainRequest();
}
xhr.upload.onprogress = function( e ) {
var percentage = 0;
if ( e.lengthComputable ) {
percentage = e.loaded / e.total;
}
return me.trigger( 'progress', percentage );
};
xhr.onreadystatechange = function() {
if ( xhr.readyState !== 4 ) {
return;
}
xhr.upload.onprogress = noop;
xhr.onreadystatechange = noop;
me._xhr = null;
me._status = xhr.status;
if ( xhr.status >= 200 && xhr.status < 300 ) {
me._response = xhr.responseText;
return me.trigger('load');
} else if ( xhr.status >= 500 && xhr.status < 600 ) {
me._response = xhr.responseText;
return me.trigger( 'error', 'server' );
}
return me.trigger( 'error', me._status ? 'http' : 'abort' );
};
me._xhr = xhr;
return xhr;
},
_setRequestHeader: function( xhr, headers ) {
$.each( headers, function( key, val ) {
xhr.setRequestHeader( key, val );
});
},
_parseJson: function( str ) {
var json;
try {
json = JSON.parse( str );
} catch ( ex ) {
json = {};
}
return json;
}
});
});