vue+element+oss实现前端分片上传和断点续传

本文介绍了如何在前端使用ali-oss库实现阿里云OSS的切片上传和断点续传功能,包括上传、暂停、恢复、取消和断点续传的详细步骤。代码示例中包含关键配置和异常处理,同时提醒注意安全问题,如使用STS临时授权和防止跨域问题。此外,还提供了网络恢复监听和Content-Type设置以确保文件预览。
摘要由CSDN通过智能技术生成

纯前端实现: 切片上传 断点续传断点续传需要在切上上传的基础上实现

前端之前上传OSS,无需后端提供接口。先上完整代码,直接复制,将new OSS里的参数修改成自己公司OSS相关信息后可用,如遇问题,请继续往下看。

oss官方文档

https://help.aliyun.com/document_detail/111268.html?spm=a2c4g.11186623.6.1111.5a583a07LknRUO

代码允许所需环境:vue + element + ali-oss

优惠券网站 https://www.cps3.cn/

安装ali-oss: cnpm install ali-oss

  • 代码实现
<template>
  <div class="dashboard-editor-container">
    <el-upload
      class="upload-demo"
      action=""
      ref="upload"
      :file-list="fileList"
      :limit="2"
      :on-change="handleChange"
      :on-remove="handleRemove"
      :auto-upload="false"
      accept=""
    >
      <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
      <el-button style="margin-left: 10px;" size="small" type="success" @click="submitForm">上传到服务器</el-button>
      <el-button style="margin-left: 10px;" size="small" type="success" @click="resumeUpload">继续</el-button>
      <el-button style="margin-left: 10px;" size="small" type="success" @click="stopUplosd">暂停</el-button>
      <el-button style="margin-left: 10px;" size="small" type="success" @click="abortMultipartUpload">清除切片</el-button>
    </el-upload>
    <el-progress :percentage="percentage" :status="uploadStatus"></el-progress>
  </div>
</template>

<script>
  let OSS = require('ali-oss') // 引入ali-oss插件
  const client = new OSS({
    region: 'oss-cn-shanghai',//根据那你的Bucket地点来填写
    accessKeyId: 'LTA*********RaXY',//自己账户的accessKeyId
    accessKeySecret: 'uu1************GiS',//自己账户的accessKeySecret
    bucket: 'a******o',//bucket名字
  });
export default {
  data () {
    return {
      fileList:[],
      file: null,
      tempCheckpoint: null, // 用来缓存当前切片内容
      uploadId: '',
      uploadStatus: null, // 进度条上传状态
      percentage: 0, // 进度条百分比
      uploadName: '',  //Object所在Bucket的完整路径
    }
  },
  mounted() {
    // window.addEventListener('online',  this.resumeUpload);
  },
  methods: {
    // 点击上传至服务器
    submitForm(file) {
      this.multipartUpload();
    },
    // 取消分片上传事件
    async abortMultipartUpload() {
      window.removeEventListener('online', this.resumeUpload)
      const name = this.uploadName; // Object所在Bucket的完整路径。
      const uploadId = this.upload; // 分片上传uploadId。
      const result = await client.abortMultipartUpload(name, uploadId);
      console.log(result, '=======清除切片====');
    },
    // 暂停分片上传。
    stopUplosd () {
      window.removeEventListener('online', this.resumeUpload) // 暂停时清除时间监听
      let result = client.cancel();
      console.log( result, '---------暂停上传-----------')
    },
    // 切片上传
    async multipartUpload () {
      if (!this.file) {
        this.$message.error('请选择文件')
        return
      }
      this.uploadStatus = null
      // console.log("this.uploadStatus",this.file, this.uploadStatus);

      this.percentage = 0
      try {
        //object-name可以自定义为文件名(例如file.txt)或目录(例如abc/test/file.txt)的形式,实现将文件上传至当前Bucket或Bucket下的指定目录。
        let result = await client.multipartUpload(this.file.name, this.file, {
          headers: {
            'Content-Disposition': 'inline',
            'Content-Type': this.file.type //注意:根据图片或者文件的后缀来设置,我试验用的‘.png’的图片,具体为什么下文解释
          },
          progress: (p, checkpoint) => {
            this.tempCheckpoint = checkpoint;
            this.upload = checkpoint.uploadId
            this.uploadName = checkpoint.name
            this.percentage = p * 100
            // console.log(p, checkpoint, this.percentage, '---------uploadId-----------')
            // 断点记录点。浏览器重启后无法直接继续上传,您需要手动触发上传操作。
          },
          meta: { year: 2020, people: 'dev' },
          mime: this.file.type
        });
        console.log(result, this.percentage, 'result= 切片上传完毕=');
      } catch (e) {
        window.addEventListener('online',  this.resumeUpload) // 该监听放在断网的异常处理
        // 捕获超时异常。
        if (e.code === 'ConnectionTimeoutError') { // 请求超时异常处理
          this.uploadStatus = 'exception'
          console.log("TimeoutError");
          // do ConnectionTimeoutError operation
        }
        // console.log(e)
      }
    },
    // 恢复上传。
    async resumeUpload () {
      window.removeEventListener('online', this.resumeUpload)
      if (!this.tempCheckpoint) {
        this.$message.error('请先上传')
        return
      }
      this.uploadStatus = null
      try {
        let result = await client.multipartUpload(this.file.name, this.file, {
          headers: {
            'Content-Disposition': 'inline',
            'Content-Type': this.file.type //注意:根据图片或者文件的后缀来设置,我试验用的‘.png’的图片,具体为什么下文解释
          },

          progress: (p, checkpoint) => {
            this.percentage = p * 100
            console.log(p, checkpoint, 'checkpoint----恢复上传的切片信息-------')
            this.tempCheckpoint = checkpoint;
          },
          checkpoint: this.tempCheckpoint,
          meta: { year: 2020, people: 'dev' },
          mime: this.file.type
        })
        console.log(result, 'result-=-=-恢复上传完毕')
      } catch (e) {
        console.log(e, 'e-=-=-');
      }
    },

    // 选择文件发生改变
    handleChange(file, fileList) {
      this.fileList = fileList.filter(row => row.uid == file.uid)
      this.file = file.raw
      // 文件改变时上传
      // this.submitForm(file)
    },
    handleRemove(file, fileList) {
      this.percentage = 0 //进度条置空
      this.fileList = []
    },
  }
}
</script>

<style scoped>
</style>

如果相关依赖已经安装完毕,但是上述代码操作时仍有报错,请检查以下问题

  const client = new OSS({
    region: 'oss-cn-shanghai',//根据那你的Bucket地点来填写
    accessKeyId: 'LT******XY',//自己账户的accessKeyId
    accessKeySecret: 'uu*********GiS',//自己账户的accessKeySecret
    bucket: 'a******io',//bucket名字
  });
  • 上述信息放在前端会存在安全问题,如在项目中使用尽量由后端接口提供。或使用STS临时授权。demo中没有,请自行探索。
    https://www.alibabacloud.com/help/zh/doc-detail/100624.htm?spm=a2c63.p38356.879954.5.7a234d04IQpf5I#concept-xzh-nzk-2gb

配置项中信息可以问后端或者运维,bucket的名字必须是你OSS上存在的且你有权限访问的,不然会一直报 Pleasr create a busket first或者一直报跨域

当遇到跨域时,或者遇到报报错信息中有etag时,请检查OSS配置,然后找有OSS服务器权限人员进行配置:

window.addEventListener('online', this.resumeUpload)用于监听网络状态(断网状态和连网状态),实现断网后恢复网络自动上传就必须设置监听。

window.removeEventListener('online', this.resumeUpload)取消监听。如果不设置取消监听,联网状态下会一直处于进行上传,因为一直满足监听条件`

headers: {
            'Content-Disposition': 'inline',
            'Content-Type': this.file.type //注意:根据图片或者文件的后缀来设置,我取得是文件的type,具体为什么下文解释
          },

'Content-Type': this.file.type`的作用:加了在文件上传完毕后,访问文件链接时可以直接查看,否则会直接下载。

文件上传完毕后查看,可以去resule.res.requestUrls中去取,但是注意要去点地址后面的 ?uploadId=******

上述代码只是demo,代码以实现功能为主,并不严谨,请自行完善。如对各位有所帮助,请推荐,谢谢各位!。

以上就是全部内容,如有疑问,敬请留言!如有问题,请指出,谢谢~~

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
断点续传是指在文件上传过程中,如果上传中断,可以从上传中断的地方开始继续上传,避免重新上传整个文件。在使用 VueElement、Axios 和 Qs 实现断点续传时,可以按照以下步骤进行操作: 1. 前端页面部分 在前端页面中,可以使用 Element 组件库来实现上传文件的功能。例如可以使用 el-upload 组件来上传文件,代码如下: ``` <template> <el-upload class="upload-demo" action="yourUploadUrl" :auto-upload="false" :on-change="handleChange" :data="uploadData" :file-list="fileList" :http-request="uploadFile" > <el-button slot="trigger" size="small" type="primary">选取文件</el-button> <el-button size="small" type="success" :disabled="!fileList.length" @click="submitUpload">上传到服务器</el-button> <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div> </el-upload> </template> ``` 在模板中,el-upload 组件的属性值中,我们需要设置以下内容: - `action` 属性:设置上传文件的地址。 - `auto-upload` 属性:设置是否自动上传。 - `on-change` 属性:设置文件上传状态改变时的回调函数。 - `data` 属性:设置上传文件时需要携带的参数。 - `file-list` 属性:设置已经上传的文件列表。 - `http-request` 属性:设置文件上传的函数,我们在这里定义上传文件的逻辑。 接下来,我们需要在 data 函数中定义 fileList 和 uploadData 对象,代码如下: ``` data() { return { fileList: [], uploadData: { chunkSize: 1024 * 1024, // 文件切片大小 chunks: 0, // 切片总数 chunkIndex: 0, // 当前切片编号 fileSize: 0, // 文件大小 fileName: '', // 文件名 fileMd5: '', // 文件md5值 uploadUrl: '', // 上传接口地址 }, } }, ``` 在这里,我们需要定义上传文件时需要携带的参数。其中,chunkSize 表示每个切片的大小,chunks 表示总共需要切片的数量,chunkIndex 表示当前上传的切片编号,fileSize 表示文件的大小,fileName 表示文件的名称,fileMd5 表示文件的 md5 值,uploadUrl 表示上传接口的地址。 然后,我们需要在 methods 函数中定义 handleChange、uploadFile 和 submitUpload 函数。其中,handleChange 函数用来监听文件上传状态的改变,uploadFile 函数用来上传文件,submitUpload 函数用来提交上传请求。代码如下: ``` methods: { handleChange(file) { this.fileList = [file] this.uploadData.fileSize = file.size this.uploadData.fileName = file.name this.uploadData.fileMd5 = 'md5' this.uploadData.uploadUrl = 'uploadUrl' this.uploadData.chunks = Math.ceil(file.size / this.uploadData.chunkSize) }, async uploadFile(file) { const index = this.uploadData.chunkIndex++ const startByte = index * this.uploadData.chunkSize const endByte = Math.min((index + 1) * this.uploadData.chunkSize, this.uploadData.fileSize) const chunkFile = file.slice(startByte, endByte) const formData = new FormData() formData.append('file', chunkFile) formData.append('chunkIndex', index) formData.append('fileName', this.uploadData.fileName) formData.append('fileMd5', this.uploadData.fileMd5) const { data } = await this.$axios.post(this.uploadData.uploadUrl, formData, { headers: { 'Content-Type': 'multipart/form-data' } }) if (index === this.uploadData.chunks - 1) { console.log('upload success') } else { this.uploadFile(file) } }, async submitUpload() { if (!this.fileList.length) return this.uploadData.chunkIndex = 0 await this.uploadFile(this.fileList[0].raw) } }, ``` 在这里,handleChange 函数将上传文件的基本信息保存到 uploadData 对象中,uploadFile 函数用来上传文件,submitUpload 函数用来提交上传请求。其中,uploadFile 函数是核心部分,它通过循环上传每个切片,如果上传成功,则继续上传下一个切片,否则重新上传当前切片。 2. 后端接口部分 在后端接口中,需要实现文件上传的逻辑。由于是断点续传,所以需要实现上传切片、合并切片的功能。例如可以使用 Node.js 和 Express 框架来实现上传文件的功能,代码如下: ``` const express = require('express') const multer = require('multer') const path = require('path') const fs = require('fs') const app = express() app.use(express.static('public')) app.post('/upload', multer({ dest: 'uploads/' }).single('file'), (req, res) => { const { fileName, fileMd5, chunkIndex } = req.body const chunkFile = req.file const chunkDir = path.join(__dirname, `./uploads/${fileMd5}`) const filePath = path.join(chunkDir, `${fileName}-${chunkIndex}`) if (!fs.existsSync(chunkDir)) { fs.mkdirSync(chunkDir) } fs.renameSync(chunkFile.path, filePath) res.json({ code: 0, message: '上传成功', }) }) app.post('/merge', (req, res) => { const { fileName, fileMd5, chunks } = req.body const chunkDir = path.join(__dirname, `./uploads/${fileMd5}`) const filePath = path.join(chunkDir, fileName) const chunkPaths = [] for (let i = 0; i < chunks; i++) { chunkPaths.push(path.join(chunkDir, `${fileName}-${i}`)) } let ws = fs.createWriteStream(filePath) chunkPaths.forEach((chunkPath) => { let rs = fs.createReadStream(chunkPath) rs.on('end', () => { fs.unlinkSync(chunkPath) }) rs.pipe(ws, { end: false }) }) ws.on('close', () => { fs.rmdirSync(chunkDir) res.json({ code: 0, message: '上传成功', }) }) }) app.listen(3000, () => { console.log('server is running at http://localhost:3000') }) ``` 在这里,我们实现了两个接口,一个是上传切片的接口 `/upload`,一个是合并切片的接口 `/merge`。其中,上传切片的接口会将上传的切片保存到指定的目录下,并返回上传成功的消息;合并切片的接口会将上传的所有切片合并成一个完整的文件,并删除上传的切片。注意,在合并切片的过程中,需要使用 fs.createWriteStream 和 fs.createReadStream 将切片合并成一个完整的文件。 以上就是使用 VueElement、Axios 和 Qs 实现文件上传断点续传的完整流程。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值