上一篇文章说了,使用 SparkMd5 来获取文件 md5 的 Hash 标识来判断是否已经上传过了,现在代码实现一下

(一)安装

在项目中安装 spark-md5

cnpm  i spark-md5 -D

代码:

element-ui 需要屏蔽其自动上传的功能,需要自己手写上传方法,上传方法写在 on-change 钩子里

<template><div><el-uploadclass="avatar-uploader"action:on-change="uploadFile":auto-upload="false":show-file-list="false":on-success="handleAvatarSuccess"><img v-if="imageUrl" :src="data:imageUrl" class="avatar"><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></div>
</template><script>
import SparkMD5 from 'spark-md5'
export default {data() {return {imageUrl: ''}},methods: {// 上传方法uploadFile(file) {// element-ui 将文件信息 { name, size, type, uid, webkitRelativePath }保存在 file.raw 字段里const isJPG = (/(png|jpeg|jpg|svg|gif|timg)/g).test(file.raw.type)if (!isJPG) {this.$message.error('上传头像图片格式错误!')return}var fileReader = new FileReader()var spark = new SparkMD5()var blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.sliceconst chunkSize = 1024 * 1024   // 文件分块 每一块2KB// Math.ceil 向上取整 如果有小数 整数加一 该文件一共多少块const chunks = Math.ceil(file.size / chunkSize)var currentChunk = 0 // 当前块数// 先去读取 才会触发 onload 将文件转成BufferfileReader.readAsArrayBuffer(file.raw)fileReader.onload = (e) => {spark.append(e.target.result)currentChunk++// 分块if (currentChunk < chunks) {var start = currentChunk * chunkSizeend = ((start + chunkSize) >= file.size) ? file.size : start + chunkSizefileReader.readAsArrayBuffer(blobSlice.call(file, start, end))} else {console.info(`${file.name} hash --->`, spark.end());}return false}}}
}
</script>

将文件上传后,可以看出获取到了该文件的hash值

现在拿到hash值之后,将hash值传给服务端,进行服务端比对,如果发现已经存在该hash值,则会发生“秒传”

服务端代码:

<template><div><el-uploadclass="avatar-uploader"action:on-change="uploadFile":auto-upload="false":show-file-list="false"><img v-if="imageUrl" :src="data:imageUrl" class="avatar"><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></div>
</template><script>
import SparkMD5 from 'spark-md5'
import axios from 'axios'
import qs from 'qs'
export default {data() {return {imageUrl: '',file: null}},methods: {// 上传方法uploadFile(file) {// element-ui 将文件信息 { name, size, type, uid, webkitRelativePath }保存在 file.raw 字段里const isJPG = (/(png|jpeg|jpg|svg|gif|timg)/g).test(file.raw.type)if (!isJPG) {this.$message.error('上传头像图片格式错误!')return}this.file = file.rawvar fileReader = new FileReader()var spark = new SparkMD5()var blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.sliceconst chunkSize = 1024 * 1024   // 文件分块 每一块2KB// Math.ceil 向上取整 如果有小数 整数加一 该文件一共多少块const chunks = Math.ceil(file.size / chunkSize)var currentChunk = 0 // 当前块数// 先去读取 才会触发 onload 将文件转成BufferfileReader.readAsArrayBuffer(file.raw)// fileReader.readAsDataURL(file.raw);fileReader.onload = (e) => {spark.append(e.target.result)currentChunk++// 分块if (currentChunk < chunks) {var start = currentChunk * chunkSizeend = ((start + chunkSize) >= file.size) ? file.size : start + chunkSizefileReader.readAsArrayBuffer(blobSlice.call(file, start, end))} else {this.upload(this.file, spark.end())}}},// 文件上传upload (file, fileHash) {const fileNameSplitArr = file.name.split('.')const ext = fileNameSplitArr[fileNameSplitArr.length - 1]// 先去服务器看看该hash值的文件是否存在axios({url: `/vertifyHash?hash=${fileHash}&ext=${ext}`,method: 'get'}).then((res) => {if (res.data.code === 1) { // 说明需要真正上传this.realUpload(fileHash, ext)} else {this.$message.success(res.data.message) // 秒传}}).catch((err) => {this.$message.error(err.message)})},// 真正上传服务器 使用formData 的方式 formData 需要自己创建!!realUpload (fileHash, ext) {let formData = new window.FormData()formData.append('File', this.file)formData.append('hash', fileHash)formData.append('ext',ext)// 注意 第一个参数 接口路径 第二个参数直接就是 formData// 不需要加请求头 浏览器会自动识别 下面就是浏览器自动加的// Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryY5jCO9bzDz1OtmaAaxios.post('/upload', formData).then((res) => {this.$message.success(res.data.message)}).catch((err) => {this.$message.success(err)})}}
}
</script>

真正需要上传的时候,把hash和后缀名也要要传过去,因为要对文件重命名

服务端代码:

const koa = require('koa')
const fs = require('fs')
const multiparty = require('multiparty')
const parse = require('co-body')
const path = require('path')
const router = require('koa-router')
const app = new koa()
const Router = new router()
app.use(Router.routes())
Router.post('/upload', async (ctx) => {var params = await parse.form(ctx.request)var form = new multiparty.Form({uploadDir: __dirname + '/upload' // 指定文件存储目录//设置单文件大小限制})// 将请求参数传入,multiparty会进行相应处理// 同时也是上传完毕后的处理// 重命名 需要命名为 [hash].[ext]form.parse(ctx.req, (err, fields, files) => {fs.rename()})ctx.body = {code: 0,message: '上传成功!'}
})
Router.get('/vertifyHash', (ctx) => {const { hash, ext } = ctx.request.query // 接受文件hash 和 文件后缀const filePath = path.join(__dirname, 'upload', `${hash}.${ext}`) // 拼接成路径const isExist = fs.existsSync(filePath) // 检查该文件是否存在// 存在就不用重复上传了,给用户返回秒传if (isExist) {ctx.body = {code: 0,message: '秒传成功'}} else { // 不存在需要重新上传ctx.body = {code: 1}}
})app.listen(3000, () => {console.log('server is running')
})

再次上传的时候,数据是这样的

令人郁闷的是,koa取不到这两个值,所以就先这样把 大致思路是对的就行了

妙传其实:并不是秒传,并没有真正的上传

文件上传:避免重复上传相关推荐

  1. layUi upload单文件上传,重复上传的问题

    今天遇到个问题,layUi upload单文件上传,选择两个不同文件时,第二次点击上传按钮还没选择上传,会把第一次上传的文件再上传一次 .在网上查到了答案,记录一下 //单个上传 upload.ren ...

  2. HDFS重复上传文件将会覆盖原文件

    HDFS重复上传文件,将会覆盖原文件.

  3. Springboot实现文件上传,并防止同文件重复上传

    目录 主要流程 编写接受文件上传的Controller 编写文件操作结果类 编写文件操作类 知识总结 参考 主要流程 在配置文件中添加文件操作的配置,示例: storage:image:#保存位置sa ...

  4. antd upload手动上传_SpringBoot 如何上传大文件?

    最近遇见一个需要上传超大大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...

  5. ajax上传 java_使用Ajax进行文件与其他参数的上传功能(java开发)

    文件上传: 记得前一段时间,为了研究Ajax文件上传,找了很多资料,在网上看到的大部分是form表单的方式提交文件,对于Ajax方式提交文件并且也要提交表单中其他数据,发现提及的并不是很多,后来在同事 ...

  6. Android开发——应用宝推广渠道出现MD5值重复,请勿重复上传

    起因 开发的小伙伴们,肯定遇到过运营的同学需要我们提供不同的推广渠道apk包.但是由于一些人为操作失误,会出现根据apk文件MD5值判断,该文件已经上传过了,请勿重复上传. 问题的出现 这是运营的同学 ...

  7. python flask上传文件_Python之利用Flask上传文件、Flask_RESTful

    Flask上传文件 回顾知识点form表单中,一旦涉及到上传文件就要就必须要有enctype属性,而且必须等于multipart/form-data.而且提交方式为'post',method = 'p ...

  8. 基于RxJava2.0+Retrofit2.0超大文件分块(分片)上传(带进度)

    当上传文件过大时,直接上传会增加服务器负载,负载过高会导致机器无法处理其他请求及操作,甚至导致宕机,这时分块上传是最佳选择.本次简单介绍两种分块上传文件方案(暂不考虑文件安全相关问题,如签名): 方案 ...

  9. 功能强大的文件上传插件带上传进度-WebUploader

    WebUploader是由Baidu WebFE(FEX)团队开发的一个以HTML5/FLASH构建的现代文件上传组件.在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用老 ...

最新文章

  1. 零基础 8 周掌握 Python,成为全能人才!
  2. 09-事务原理和自动提交设置
  3. 传统企业向产业互联网转型的两条路径
  4. 首次公开:京东数科强一致、高性能分布式事务中间件 JDTX
  5. 检查DISPLAY设置时Xlib出现No protocol specified错误
  6. python timeit用法_十大Python开发技巧
  7. opencv实现几幅图像拼接成一整幅大图
  8. Python使用pandas读取Excel文件多个WorkSheet的数据并绘制柱状图和热力图
  9. 安装pycharm报nse.impl.GeneralLicenseManager - No valid license found错解决方案
  10. Memcached实战之单机部署----单实例/多实例
  11. allegro里面由于shape out of date
  12. 番外2. OpenCV 中摄像头捕获与视频处理与常见问题解决方案
  13. 操作系统——大题——空闲分区表问题
  14. 微信发布的辟谣小程序
  15. c语言怎么编程24小时制,[C语言][PTA] 7-7 12-24小时制
  16. opencv 骨架提取/图片细化 代码
  17. linux 多点触摸屏测试,c – Linux中的多点触控
  18. php去除换行符的方法
  19. mysql utl_file_利用UTL_FILE包实现文件I/O操作
  20. SAP ABAP PARAMETERS定义下拉列表

热门文章

  1. angular js 循环数据(死数据) 添加数据 隔行换色 单个删除 排序
  2. 戳对地方,葛优躺秒变工作狂
  3. 【SCOI 2005】骑士精神
  4. Matlab不同版本的系统需求(不同操作系统下的)、所支持的编译器查找
  5. Linux 服务器设置成支持中文
  6. 5月华熙LIVE·五棵松荣获两项大奖
  7. 人大金仓国产化数据库适配
  8. 爬虫从入门到精通(15) | 使用Python-OCR识别库对图形验证码进行识别
  9. 奉劝大家不要再用刷流量软件刷新浪博客等级了
  10. springcloud五大神兽之Eureka介绍