前端minio签名直传视频大文件

开发步骤

  1. 前端通过接口传文件名称给后端
  2. 后端生成签名 url 和 uuid 给到前端
  3. 前端使用 xhr 调用 minio 签名直传接口,完成大文件上传
  4. 前端根据 uuid 获取上传文件回显到页面
  5. 直传无法提供进度条,前端可根据宽带大致计算

文件上传实现

  getPreSignedPutUrl({ fileName: file.name }).then(res => {
    const uuid = res.data.uuid
    // file 直接传,不要用 Formdata,否则文件打不开
    axios.put(res.data.url, file, {
      headers: { 'Content-Type': 'multipart/form-data' }
    }).then(_ => {
      
      getMinioFile({ uuid }).then(res => {
        this.videoFile = res.data
      }).catch(_ => {})

    }).catch(_ => {
      this.$message.error('上传错误,请稍后再试!')
      this.videoLoading = false
    })
  }).catch(_ => {
    this.videoLoading = false
  })

优化体验!前端实现进度条

  const fileSizeM = parseInt(file.size / 1024 / 1024)
  let timerId
  if (fileSizeM < 10) {
    this.filePercentage = 50
  } else {
    // 若按照 1 秒 10M 显示进度条,1024M 约需要 102 秒
    const second = parseInt(fileSizeM / 10)
    console.log('second', second)
    // 这里计算每秒的进度条,100 / 102,每秒进度 +0.98 左右
    // roundTo 保留小数点后两位方法,请看完整代码
    const count = this.roundTo(100 / second, 2)
    console.log('count', count)
    timerId = setInterval(() => {
      this.filePercentage += count
      this.filePercentage = this.roundTo(this.filePercentage, 2)
      console.log('this.filePercentage', this.filePercentage)
      if (this.filePercentage > 99) {
        this.filePercentage = 99
        clearInterval(timerId)
      }
    }, 1000)
  }

完整代码

import axios from 'axios'
import { getPreSignedPutUrl, getMinioFile } from '@/api/xxx.js'

export default {
  data() {
    return {
      videoLoading: false,
      filePercentage: 0,
      videoFile: {}
    }
  },
  methods: {
    roundTo(num, decimals) {
      const factor = Math.pow(10, decimals);
      return Math.round(num * factor) / factor;
    },
    minioVideoRequest(event) {
      const file = event.file

      getPreSignedPutUrl({ fileName: file.name }).then(res => {

        const fileSizeM = parseInt(file.size / 1024 / 1024)
        let timerId
        if (fileSizeM < 10) {
          this.filePercentage = 50
        } else {
          const second = parseInt(fileSizeM / 10)
          const count = this.roundTo(100 / second, 2)
          timerId = setInterval(() => {
            this.filePercentage += count
            this.filePercentage = this.roundTo(this.filePercentage, 2)
            if (this.filePercentage > 99) {
              this.filePercentage = 99
            }
          }, 1000)
        }

        const uuid = res.data.uuid
        axios.put(res.data.url, file, {
          headers: { 'Content-Type': 'multipart/form-data' }
        }).then(_ => {
          clearInterval(timerId)
          this.filePercentage = 100
          setTimeout(() => {
            this.filePercentage = 0
            this.videoLoading = false
          }, 500)
          
          getMinioFile({ uuid }).then(res => {
            this.videoFile = res.data
          }).catch(_ => {})

        }).catch(_ => {
          this.$message.error('上传错误,请稍后再试!')
          clearInterval(timerId)
          this.filePercentage = 0
          this.videoLoading = false
        })
      }).catch(_ => {
        this.videoLoading = false
      })
    },
  }
}
  <el-form-item label="上传视频:" required>
    <el-upload
      :show-file-list="false"
      :http-request="minioVideoRequest"
      action=""
      accept="video/*"
    >
      <el-button type="primary" size="small" :loading="videoLoading">本地上传</el-button>
    </el-upload>
    <div class="video-file">
      <el-progress :percentage="filePercentage" v-if="videoLoading" />
      <div v-if="videoFile.name">
        <span>{{ videoFile.name }}</span>
      </div>
    </div>
  </el-form-item>

验证:100M,11秒左右

请添加图片描述

### MinIO 前端直传 400 错误解决方案 当遇到MinIO前端直传返回400错误的情况时,通常是因为请求不符合预期或是存在配置上的问题。以下是几种可能的原因及其对应的解决方法: #### 请求头不匹配 如果发送到MinIO的HTTP头部信息与期望不符,则可能会触发400 Bad Request响应。确保所有的必要字段都已正确设置,特别是`Content-Type`和认证相关的头部。 对于使用预签名URL的方式来说,任何额外参数或自定义元数据都需要被恰当地编码并加入到查询字符串中[^1]。 ```javascript // JavaScript示例:创建带有适当header的XMLHttpRequest对象 var xhr = new XMLHttpRequest(); xhr.open('PUT', presignedUrl, true); xhr.setRequestHeader('Content-Type', 'application/octet-stream'); xhr.send(fileBlob); // 发送文件二进制流 ``` #### 预签名URL过期时间不足 预签名URL的有效期限应该足够长以完成整个上传过程。可以通过调整生成预签名链接时指定的时间窗口来解决问题。 ```python import boto3 from datetime import timedelta s3_client = boto3.client( service_name='s3', endpoint_url='http://localhost:9000', aws_access_key_id='minio', aws_secret_access_key='minio123' ) presigned_post = s3_client.generate_presigned_post( Bucket='mybucket', Key='mykey', ExpiresIn=timedelta(hours=1).total_seconds() # 设置有效期为一小时 ) ``` #### 文件大小超出限制 某些情况下,默认的最大允许上传尺寸可能导致较大文件无法成功传输而引发此错误。可以在启动容器时通过环境变量`MINIO_MAX_UPLOAD_SIZE`设定更大的上限值。 ```bash docker run -p 9000:9000 \ -e "MINIO_ACCESS_KEY=minio" \ -e "MINIO_SECRET_KEY=minio123" \ -e "MINIO_MAX_UPLOAD_SIZE=5G" \ # 设定最大上传量为5GB -v /mnt/data:/data \ -v /mnt/config:/root/.minio \ minio/minio server /data ``` #### CORS策略缺失或不当 跨域资源共享(CORS)政策未正确定义也可能阻碍来自不同源站发起的请求。确认已在MinIO实例上设置了合适的CORS规则以便支持所需的HTTP操作。 ```json { "CORSRules": [ { "AllowedOrigins": ["*"], "AllowedMethods": ["GET", "POST", "PUT"], "MaxAgeSeconds": 3000, "ExposeHeaders": [], "AllowedHeaders": ["Authorization"] } ] } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值