实现网页文件断点上传

关于文件的断点上传,网上的很多例子,有好有坏吧。最失望的是,在知网下载了十篇论文,感觉都是在瞎扯淡,目测是大学生的毕业设计吧,反正很失望。

主要是剖析了腾讯邮箱的文件上传,发现和我自己实现的大致相同,所以直接分析腾讯邮箱的上传吧。

基本概念

文件上传主要是利用了文件内容进行哈希运算,最终得到一个哈希字符串来当做文件的唯一签名。

利用文件的签名还可以实现快传。

  1. 什么是快传?

    • 简单的说就是当一个文件已经存在于服务器上,再次上传该文件时,可以通过文件签名判断是否存在,如果存在直接返回上传成功,用户就会感到一下子就上传好了,这就是快传。
  2. 实现断点上传的问题

    • 断点上传需要前端进行文件签名计算,而js进行计算是效率很低的一件事,影响用户体验。
  3. 既然js计算效率,怎么解决?

    • 目前我是找了一个很高效的库来提高效率,效率还是挺不错。感谢ph2给我找的这个库。点击链接下载查看
开始分析腾讯邮箱文件上传

1 打开浏览器控制台并上传文件,如图
可以看到看到该请求与返回值,

  • exist用于判断文件是否存在,exist=0说明没有上传过,exist=1说明上传过
  • sFileId应该就是该文件的id
  • sIp可能是文件上传的服务器地址
  • sKey就是用于加密的身份秘钥
  • sMailId可能就是我的邮箱的某个id吧,每次上传都不一样,对我也不重要

再看请求值 这里是获取了文件的size,md5,sha

{
    "path":"hh.txt",
    "appid":"",
    "size":16933060,
    "md5":"59bc1883c7879c31e555197786f3b360",
    "sha":"981992c1ae468d79fa4f0a47268a5e262fea166f",
    "sha3":""
}

服务器就通过了md5,sha可能还加上了size来判断文件的是否存在。

为什么需要md5和sha两个哈希值来判断文件的唯一性,巴拉巴拉等等原因就因为会发生哈希碰撞,而且MD5已经被声明不是一个很安全的散列算法了,当然,不安全对我们普通程序员来说,也没简单易行省时省力的办法让他进行碰撞。

2 ftn_hander在干什么?

首先POST方法是肯定的,在请求头里:

  • Content-Length: 请求数据的长度
  • DATA-MD5字段,这个MD5是上传的每个片段的MD5值

首先的一个概念,断点上传,是将一个大文件,切分为多个小片段,然后一个片段接一个的上传。为了防止文件传输过程中被篡改,最简单的方法就是对每一个片段进行哈希运算当做片段的签名,然后服务器对每一个片段进行检验,这里只做了MD5的验证。

然后第二个红框这部分的乱码内容,就需要自行查看js源码了,主要的内容大概就是对上文中的sFileId, sKey,sMailId 有没有MD5忘记了,等等几个值分别计算编码,最终得到这样一个乱码,然后这个乱码再加上文件内容,最后提交到服务器,服务器在解码验证。

3 等待文件上传完成
文件上传完成,并且验证通过,那就上传成功咯,否则就返回错误咯。

每一个分片上传完成后,返回了这样一个玩意儿。时间已经过去一个多月了,我忘记了这玩意是说什么的,但是映象中是返回了下一个文件片段的偏移量和当前上传状态状态值(是否上传完成)。

文件分片上传时,每一个分片上传后都会返回一个偏移量,就是服务器接收到了多少数据,下一个数据需要从原文件的多少个字节开始传递。

比如一个文件100字节,分片大小为16字节,已经上传了32字节。继续上传时上传了0-16字节,服务器会拒绝这段数据并返回一个偏移量33给你,告诉你要从33开始上传,于是上传了33-48字节,服务器又会返回49给你。直到文件上传完成。

4 关于断点上传前端兼容性
关于兼容性读取文件后需要用到js的blob,但是blob是有兼容性问题的,所以对IE,目测只能写浏览器插件了。

到此,分步分析文件上传就是如上所说了。

细节内容补充

1 每次上传文件不论文件是否上传,都会先上传本地文件前64KB的文件,如果文件已上传完成,则返回成功,否则继续上传未上传完的内容,继续上传时,分片大小为512KB。


我一直想不明白上传重复文件时为什么还是需要上传60KB,因为第一个请求uploadunite就已经可以告诉前端文件是否上传过,是否上传完成,若没上传完成,可以直接返回偏移量,所以上传重复文件时还要再上传60KB,感觉没必要。