最近做了一个H5上传视频项目,以下对这次项目的总结,如果错误或不合适的地方,请拍砖。
总结包括:
特点:多任务上传、续传
一、上传协议
协议内容:
POST /upload HTTP/1.1
Host: example.com
Content-Length: 51201
Content-Type: application/octet-stream
Content-Disposition: attachment;filename="big.TXT"
X-Content-Range: bytes 0-51200/511920
Session-ID: 1111215056
详细规则请查看RFC2616规范,需要指出的是
Content-Dispostion中的filename需要 encodeURIComponent编码。
二、上传流程
-
选择文件;
-
从三个维度(数量、大小、格式),判断选择文件的是否合格,如果不合格,派发事件onError;
-
遍历filelist进行通过第4步包装获取fileObj,然后派发onAdd事件。每个fileObj含有
属性列表:
fileName:文件名
fileSize:文件大小
idx: 文件的唯一标识(现阶段只是时间戳生成)
file:当前的file对象
方法列表:
cancel: 取消上传,会派发事件onRemove
del: 删除vid对应的视频
upload: 上传该文件
-
当调用fileObj的upload方法时,会根据file的fileName和fileSize通过接口获取上传的服务器地址,还有一个比较重要的参数alreadySend,文件上传的起始值,如果之前没有上传过,则为0,如果有,则从该值开始上传(表现为续传)。返回的接口如下:
{
"code":"A0001",
"msg":"",
"data":[
{
"vid":78582771,
"alreadySend"0, // 文件上传的起始值
"fileName":"test.mp4",
"fileSize":"4455435",
"upload_url":"http:\/\/2.131.133.51/" // 服务器地址
}
],
"serverTime":1369200769 // 服务器时间
}
5.设置file的fileSendStart属性,如果是首次请求,则为上一步中的alreadySend值,并派发onStart事件;
6.根据file的fileSendStart值对文件进行切片,返回newFileBlob,如果设每片大小X,则
fileSendEnd = fileSendStart + X;
newFileBlob = file.slice(fileSendStart,fileSendEnd); // 此为半闭区间,所切大小不包括 fileSendEnd 值
7.建立XMLHttpRequest请求,根据上传协议,监听并发送上一步切片所得到的newFileBlob,发送成功后,设置fileSendEnd为上一步中的fileSendStart,重复上一步;如下是对XMLHttpRequest.onreadystatechange的监听状态列表:
| 类别 |
readyState |
status |
fileSendStart |
原因 |
| 1 |
4 |
201 |
|
一片上传完成,继续上传,并上报上传进度 |
| 2 |
4 |
200 |
|
整体上传完成,停止上传,并派发事件`onSuccess` |
| 3 |
4 |
0 |
0 |
跨域失败,派发事件`onFail` |
| 4 |
4 |
0 |
>0 |
接口abort,派发事件`onFail` |
| 5 |
4 |
其它 |
|
异常失败,派发事件`onFail` |
另外还有:
对XMLHttpRequest.onprogress事件进行监听,派发onUploading事件;
表中的上报进度,避免多次请求,可进行限制,如20M进行一次上报等;
当对file对象进行cancel操作时,要主动abort此次请求,为避免多次事件派发,当cancel时,不派发onFail事件;
三、事件列表
事件参数对象统一为,可根据事件类型再添加,比如在上传中,可以根据需求添加上传速度、上传剩余时间等参数:
{
code: '', // 异常或失败的状态类型码
msg: '', // 异常或失败的状态类型值
list: [
{
idx: '', // 唯一标识
fileName: '', // 文件名
fileSize: '', // 文件大小
suffix: '', // 后缀
file: '' // file对象
}
]
}
| 名称 | 派发条件 |
| onAdd | 添加文件时 |
| onStart | 开始上传时,获取到上传地址后 |
| onRemove | 上传过程中,取消上传时 |
| onUploading | 上传中 |
| onFail | 上传过程中造成的失败(不包括用户abort请求时造成的onFail |
| onError | 上传前的异常,包括文件类型、大小、数量不正确等 |
四、其它
-
获取上传地址,用fileName和fileSize进行组合来当唯一标识,不太靠谱,推荐使用
唯一标识 = fileName+fileSize+file.lastModified;
加上lastModified,不过官方文档上说,此值有可能为null,不过对于大部分文件的限制已经比文件名+大小提高了很多。当然也可以通过fileReader读取文件的某一部分,用对其它进行加密后的MD5值做为唯一标识(并未实践)。
PS: 当唯一标识精确后,理论上可以实现离线上传即秒传。
-
在验证文件格式的操作,推荐使用JS验证,当然也可以放在云端,页面加载时,JS去获取;
-
XMLHttpRequest请求时,超时时间的时间要看你一次抛多大的块给服务器,最少也不要少于60秒.
-
Blob的slice方法是半闭区间,x-content-range是全闭区间。关于slice,再推荐看下:http://t.cn/zHyE8dZ
最近做了一个H5上传视频项目,以下对这次项目的总结,如果错误或不合适的地方,请拍砖。
总结包括:
特点:多任务上传、续传
一、上传协议
协议内容:
详细规则请查看RFC2616规范,需要指出的是
Content-Dispostion中的filename需要encodeURIComponent编码。二、上传流程
选择文件;
从三个维度(数量、大小、格式),判断选择文件的是否合格,如果不合格,派发事件
onError;遍历
filelist进行通过第4步包装获取fileObj,然后派发onAdd事件。每个fileObj含有属性列表:fileName:文件名fileSize:文件大小idx: 文件的唯一标识(现阶段只是时间戳生成)file:当前的file对象方法列表:cancel: 取消上传,会派发事件onRemovedel: 删除vid对应的视频upload: 上传该文件当调用
fileObj的upload方法时,会根据file的fileName和fileSize通过接口获取上传的服务器地址,还有一个比较重要的参数alreadySend,文件上传的起始值,如果之前没有上传过,则为0,如果有,则从该值开始上传(表现为续传)。返回的接口如下:5.设置file的
fileSendStart属性,如果是首次请求,则为上一步中的alreadySend值,并派发onStart事件;6.根据file的
fileSendStart值对文件进行切片,返回newFileBlob,如果设每片大小X,则7.建立
XMLHttpRequest请求,根据上传协议,监听并发送上一步切片所得到的newFileBlob,发送成功后,设置fileSendEnd为上一步中的fileSendStart,重复上一步;如下是对XMLHttpRequest.onreadystatechange的监听状态列表:另外还有:
对
XMLHttpRequest.onprogress事件进行监听,派发onUploading事件;表中的上报进度,避免多次请求,可进行限制,如20M进行一次上报等;
当对file对象进行cancel操作时,要主动abort此次请求,为避免多次事件派发,当cancel时,不派发
onFail事件;三、事件列表
事件参数对象统一为,可根据事件类型再添加,比如在上传中,可以根据需求添加
上传速度、上传剩余时间等参数:四、其它
获取上传地址,用
fileName和fileSize进行组合来当唯一标识,不太靠谱,推荐使用加上
lastModified,不过官方文档上说,此值有可能为null,不过对于大部分文件的限制已经比文件名+大小提高了很多。当然也可以通过fileReader读取文件的某一部分,用对其它进行加密后的MD5值做为唯一标识(并未实践)。PS: 当唯一标识精确后,理论上可以实现
离线上传即秒传。在验证文件格式的操作,推荐使用JS验证,当然也可以放在云端,页面加载时,JS去获取;
XMLHttpRequest请求时,超时时间的时间要看你一次抛多大的块给服务器,最少也不要少于60秒.Blob的slice方法是半闭区间,x-content-range是全闭区间。关于slice,再推荐看下:http://t.cn/zHyE8dZ