全部
常见问题
产品动态
精选推荐

前端实现分片上传功能

管理 管理 编辑 删除

前言:每次上传遇到大文件,上传速度和上传后接口响应都比较慢,为了提高用户体验,减少用户的等待时间,缓解服务器的压力。我们    对大文件进行了分片上传,下面的具体思路和完整代码,有需要的小伙伴可以看看。

实现思路:

1. 文件 MD5 加密

MD5 是文件的唯一标识,可以利用文件的 MD5 查询文件的上传状态。

根据文件的内容、文件名称、文件大小等信息,通过 spark-md5[2] 生成文件的 MD5。

2. 文件分片

文件上传优化的核心就是文件分片,Blob 对象中的 slice 方法可以对文件进行切割,File 对象是继承 Blob 对象的,因此 File 对象也有 slice 方法。看自己项目需要设置分片大小,我们分片大小和后端约定是5MB。

3. 上传分片

上传所有的切片,将切片序号、切片文件、文件 MD5 传给后台。

后台接收到上传请求后,首先查看名称为文件MD5 的文件夹是否存在。


思路很简单,实现起来大家肯定各自有难度,下面的完整的代码,结合不同项目可以参考一下:

import SparkMD5 from 'spark-md5'
import request from '@/api/request'

/**
 * 分片上传
 * @param {Object} file- 文件内容
 * @param {Object} option- 需要给后端的参数
 * @param {String} url-上传给后台的接口地址
 */

export const uploadByPieces = (file, option, url) => {

  return new Promise(async (resolve, reject) => {
    // 1. 读取文件的md5
    let fileMD5
    let fileRederInstance = new FileReader()
    fileRederInstance.readAsBinaryString(file)
    fileRederInstance.addEventListener('load', (e) => {
      let fileBolb = e.target.result
      fileMD5 = SparkMD5.hashBinary(fileBolb)
      readChunkMD5(file, fileMD5, option)
    })

    // 2. 针对每个文件进行chunk处理
    const readChunkMD5 = async (file, md5, option) => {
      const chunkSize = 5 * 1024 * 1024 // 5MB一片
      const chunkCount = Math.ceil(file.size / chunkSize) // 总片数
      for (var i = 0; i < chunkCount; i++) {
        const { chunk } = getChunkInfo(file, i, chunkSize)
        await uploadChunk({ chunk, currentChunk: i, chunkCount, md5 }, option)
      }
    }
    
    const getChunkInfo = (file, currentChunk, chunkSize) => {
      let start = currentChunk * chunkSize
      let end = Math.min(file.size, start + chunkSize)
      let chunk = file.slice(start, end)
      chunk = blobToFile(chunk, file.name)
      return { start, end, chunk }
    }
    
    // Blob 转 File
    const blobToFile = (blob, fileName) => {
      const file = new File([blob], fileName, { type: blob.type })
      return file
    }
    
    // 3. 上传分片文件
    const uploadChunk = (chunkInfo, option) => {
      // 创建formData对象,下面是结合不同项目给后端传入的对象。
      let formData = new FormData()
      if (Object.keys(option).length > 0) {
        for (let key in option) {
          formData.append(key, option[key])
        }
      }
      formData.append('file', chunkInfo.chunk)
      formData.append('md5', chunkInfo.md5)
      formData.append('chunk_index', chunkInfo.currentChunk)
      formData.append('chunk_total', chunkInfo.chunkCount)
      request
        .post(url, formData)
        .then((res) => {
          if (res.data.src) {
            resolve(res)
          } else if (res.status !== 200) {
            reject(res)
          }
        })
        .catch((e) => {
          reject(e)
        })
    }
  })
}



请登录后查看

怎么网名又被占用了 最后编辑于2024-11-05 10:09:37

快捷回复
回复
回复
回复({{post_count}}) {{!is_user ? '我的回复' :'全部回复'}}
排序 默认正序 回复倒序 点赞倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level }}

作者 管理员 企业

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推荐': '推荐'}}
{{item.is_suggest == 1? '取消推荐': '推荐'}}
沙发 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暂无简介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
{{item.like_count}}
{{item.showReply ? '取消回复' : '回复'}}
删除
回复
回复

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回复 {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回复' : '回复'}}
删除
回复
回复
查看更多
509
{{like_count}}
{{collect_count}}
添加回复 ({{post_count}})

相关推荐

快速安全登录

使用微信扫码登录
{{item.label}} {{item.label}} {{item.label}} 板块推荐 常见问题 产品动态 精选推荐 首页头条 首页动态 首页推荐
加精
取 消 确 定
回复
回复
问题:
问题自动获取的帖子内容,不准确时需要手动修改. [获取答案]
答案:
提交
bug 需求 取 消 确 定

微信登录/注册

切换手机号登录

{{ bind_phone ? '绑定手机' : '手机登录'}}

{{codeText}}
切换微信登录/注册
暂不绑定
CRMEB客服

CRMEB咨询热线 咨询热线

400-8888-794

微信扫码咨询

CRMEB开源商城下载 源码下载 CRMEB帮助文档 帮助文档
返回顶部 返回顶部
CRMEB客服