最近做了3个多月的上传终于要告一段落了(其实远远没有。。。),遇到的问题都不是很大,但总归做了一次文件上传,还是要总结一下。

问题一:

内存问题,这次上传并没有用断点续传功能,所以文件都是一次传输的,也就是一次传送一个可能是2G的问题,那就有可能对于内存占用产生问题。
好吧,这个问题我并没有找到答案,但是据我观察Chrome浏览器,并没有出现内存占用过大现象,而是不断攀升到一个峰值,然后降下来了,我猜测,由于H5用的是XHR原声的API,浏览器在实现此协议时已经做了内存占用的优化,所以不必担心。

问题二:

进度条问题,由于用了xhr的原生API,其中可以监控进度。但是这个进度是浏览器把二进制文件发出去的进度,并不表示服务器收到了,因此这个进度是不准确的,尤其是到最后100%时就看出来了,前端判断上传完成了,但是需要后端返回全部接受成功的消息才能真正判断上传成功,而这个返回一定会比进度100%晚。
观察一般网站的做法是显示【正在存储中。。。】、【请稍后。。。】等等。而我们的转码部门用了Nginx上传模块,自带一段可以查进度的代码,但是这样的只能用ajax轮训查询的方式,客户端压力很大。因此,之后的解决方式是传到95%之后,再用轮训去矫正进度。
如果用分片上传可能就会缓解这个问题了,可以一片片地确定返回,从而计算进度。

H5 上传核心代码:

//采用XHR2标准的API,可以异步上传二进制文件。
xhr = new XMLHttpRequest();
//上传进度回调
xhr.upload.onprogress = function(e){
	//lengthComputable是一个表示进度信息是否可用的布尔值
    if ( e.lengthComputable ) {
        var percentNum = (blobSize.start + e.loaded) / t.fileSize;
        // 派发进度
    }
};
xhr.onreadystatechange = function(){
    if (xhr.readyState == 4) {
        // 跨越请求未成功
        if(lastReadyState == 1 && xhr.status == 0 && loadedByte == 0){}
    	
        if ( xhr.status == 201 ) {
        	// 响应成功
    	} else if (xhr.status == 200 && $.parseJSON(xhr.responseText).state == 'success') {
    		//返回成功,并接收到服务器存储成功的响应
    	}
    }
  };
//post 过去,写好地址
xhr.open("POST", obj.upload_url + '&' + 'X-Progress-ID='+obj.upload_id );
// 添加头信息.
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.setRequestHeader('Content-Disposition', 'attachment; name=\"file\";');
xhr.setRequestHeader('X-Content-Range', 'bytes ' + blobSize.start + '-' + blobSize.end + '/' + encodeURIComponent(t.fileSize));
xhr.setRequestHeader('Session-ID', obj.vid);
   	//发送啦!
xhr.send(blob);

关于协议的注意事项:

协议是与数据接受方进行的约定,一般约定有如下几下:
跨越约定:XHR2 支持跨越传送,不过需后端设置一下;
文件类型( Content-type ),如无指定,则为application/octet-stream ;
附件信息( Content-Disposition ),指定文件名(需要进行encodeURIComponent 编码)
传送的区间( X-Content-Range )一般用XHR2传送数据,都会对文件的Blob进行切片,切片后,需要告诉后端,此片Blob 的区间。
标识(Session-ID),此次传送的数据的唯一标识
XMLHttpRequest.onreadystatechange 返回相应的状态:
readyState status file send Start 可能原因
4 201 - 一片上传完成
4 200 - 事件上传完成
4 0 0 跨越失败
4 0 >0 接口abort
4 其它 - 其它异常、错误造成的失败

参考资料:

HTML5文件上传组件的深度剖析

Ngingx HttpUploadModule

记于2014年06月17日 EOF