为了阅读和开发方便,我将文件上传系列相关文章章节列出来,建议从01节开始看起,文章内容按顺序紧紧相连:
01.使用vue-simple-uploader上传文件和文件夹
02.文件分片上传之前端文件分片
03.文件分片上传之后端PHP合成文件
04.超大文件上传之计算文件MD5值
05.文件上传之秒传文件
06.文件上传之断点续传和跨端续传
本系列文章相关源码已经上传到github上,请参照下载:https://github.com/lrfbeyond/fast-uploader
前面说了,因为服务端已经知道文件已经存在服务器端了,也就是说我们要传的这个文件,此前已经至少上传过一次了。这个文件有可能是我们自己上传的,也有可能是别人上传的。
这正是用户需要的,秒传文件,节省上传时间。对后端服务器来说,节约存储空间,同样的文件没必要存成多个文件,同时也节约带宽,当然是好事了。
那服务端是如何知道文件已经上传过了呢?
答案就是MD5。在上一节中我们知道上传前要检测文件md5值。那么本节文章我们将给您介绍如何在文件上传时将md5告诉后端,后端程序如何判断文件已经上传的?
1.前端计算好文件md5,并将md5赋值给文件唯一标识:file.uniqueIdentifier
。
2.前端向后端发送一个get请求,携带md5值,询问后端是否该秒传文件。
3.验证md5,即后端PHP从mysql表中查询是否含有该文件md5值的文件记录,如果有,则返回秒传标识。
4.如果mysql表中没有该文件md5值记录,则按正常上传流程继续上传文件。
5.上传完成后,将该文件md5值记录到数据表中,以便下次验证md5。
1.本文前端基于vue-simple-uploader上传组件,如果您还不了解该组件,请先查看本系列文章01节相关内容。
2.本文后端使用php+mysql,您需要具备相关知识。
3.在mysql数据库中建立hw_file表,表结构如下:
DROP TABLE IF EXISTS `hw_file`; CREATE TABLE `hw_file` ( `id` int(11) NOT NULL AUTO_INCREMENT, `filename` varchar(255) NOT NULL COMMENT \'文件名\', `filesize` int(11) NOT NULL DEFAULT \'0\' COMMENT \'文件大小\', `md5` varchar(32) NOT NULL COMMENT \'文件md5\', `type` varchar(10) NOT NULL COMMENT \'文件类型\', `filepath` varchar(128) NOT NULL COMMENT \'文件保存路径\', `created_at` datetime NOT NULL COMMENT \'上传时间\', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8mb4;
首先,确保开启了服务端分片校验功能,这个功能在vue-simple-uploader的options选项中设置,testChunks: true
, 默认是true开启状态的。
接着选中文件,准备上传前需要计算该文件的md5,关于md5的计算请查看上一节文章。
开启了分片校验功能,目的是每次在正式上传前先向后端发送个get请求,用来实现秒传、续传功能的。
在这个get请求中,在url中会携带文件的md5等相关信息一起传给后端。
在后端验证好文件md5后,会返回相应的是否秒传的标识isExist
,前端要识别这个标识,并及时更新文件上传状态。
在options选项中添加函数checkChunkUploadedByResponse()
,该函数响应后台返回message信息,同时检测分片信息是否上传完整,在后面的断点续传章节会讲到验证分片。
// 服务器分片校验函数 checkChunkUploadedByResponse: (chunk, message) => { let obj = JSON.parse(message); if (obj.isExist) { this.statusTextMap.success = \'秒传文件\'; return true; } },
很显然,当检测到obj.isExist
是true的时候,则表明文件已经存在了,这是直接将文件的上传状态改成:“秒传文件”,并结束上传。
我们还是继续上一节的后端php文件:Uploader.php。
在获取到前端请求过来的参数中,文件唯一标志identifier
就是该文件的md5值。然后根据该文件的md5值和该文件的大小filesize,这两个参数,查询hw_file表,得到满足md5和filesize都相当的记录,如果存在记录,则该文件已经上传过了。返回秒传标识:isExist = true
以及文件路径。如果文件不存在,那么就开始上传文件。
//检测断点和md5 public function checkFile() { $identifier = $this->fileInfo[\'identifier\']; //检测文件md5是否已经存在 $rs = $this->checkMd5($identifier, $this->fileInfo[\'totalSize\']); return $rs; } //检测md5表是否已存在该文件 private function checkMd5($md5, $filesize) { $db = self::mysql(); $sql = "SELECT count(*) as t,filepath FROM `hw_file` WHERE md5=:md5 AND filesize=:filesize"; $stmt = $db->prepare($sql); $stmt->execute([ \':md5\' => $md5, \':filesize\' => $filesize ]); $row = $stmt->fetch(PDO::FETCH_ASSOC); $count = $row[\'t\']; if ($count > 0) { $res[\'isExist\'] = true; $res[\'filepath\'] = $row[\'filepath\']; } else { $res[\'isExist\'] = false; } return $res; }
运行后,从前端选中文件上传,第一次上传成功:
第二次选择同一个文件上传,或者将文件改名再上传,或者换个浏览器换个终端上传同一个文件,都会是秒传的效果:
好了,关于秒传我们就先讲到这里,前后端的具体代码已经上传到github上了,请直接下载运行。
接下来一篇文章,我会介绍如何实现断点续传,跨终端续传文件,敬请关注。
本文地址:https://www.stayed.cn/item/278
转载请注明出处。
本站部分内容来源于网络,如侵犯到您的权益,请 联系我