Skip to content

H5上传逻辑总结 #1

Description

@stri

最近做了一个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编码。

二、上传流程

  1. 选择文件;

  2. 从三个维度(数量、大小、格式),判断选择文件的是否合格,如果不合格,派发事件onError;

  3. 遍历filelist进行通过第4步包装获取fileObj,然后派发onAdd事件。每个fileObj含有

    属性列表:

    fileName:文件名

    fileSize:文件大小

    idx: 文件的唯一标识(现阶段只是时间戳生成)

    file:当前的file对象

    方法列表:

    cancel: 取消上传,会派发事件onRemove

    del: 删除vid对应的视频

    upload: 上传该文件

  4. 当调用fileObjupload方法时,会根据file的fileNamefileSize通过接口获取上传的服务器地址,还有一个比较重要的参数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上传前的异常,包括文件类型、大小、数量不正确等

四、其它

  1. 获取上传地址,用fileNamefileSize进行组合来当唯一标识,不太靠谱,推荐使用

    唯一标识 = fileName+fileSize+file.lastModified;
    

    加上lastModified,不过官方文档上说,此值有可能为null,不过对于大部分文件的限制已经比文件名+大小提高了很多。当然也可以通过fileReader读取文件的某一部分,用对其它进行加密后的MD5值做为唯一标识(并未实践)。

    PS: 当唯一标识精确后,理论上可以实现离线上传即秒传。

  2. 在验证文件格式的操作,推荐使用JS验证,当然也可以放在云端,页面加载时,JS去获取;

  3. XMLHttpRequest请求时,超时时间的时间要看你一次抛多大的块给服务器,最少也不要少于60秒.

  4. Blobslice方法是半闭区间,x-content-range是全闭区间。关于slice,再推荐看下:http://t.cn/zHyE8dZ

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions