前端直接上传文件到minio

前端上传文件到minio


项目有需要前端来直接上传文件到minio,由于这里我没看懂官网的文档,所以直接在网上搜的教程,这里主要是讲述一下我遇到的一些问题

1. 实现步骤

下面的代码是我搜到的比较简短的实现步骤

<template>
  <div>
    <input type="file" @change="onFileChange" />
    <button @click="uploadFile" :disabled="!file">上传</button>
    <div v-if="progress > 0">上传进度: {{ progress }}%</div>
    <div v-if="error" style="color: red;">错误: {{ error }}</div>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      file: null,
      progress: 0,
      error: null,
    };
  },
  methods: {
    onFileChange(event) {
      this.file = event.target.files[0];
    },
    async uploadFile() {
      if (!this.file) return;

      const url = 'http://<minio-server-url>/<bucket-name>/<object-name>'; // 替换为实际的 MinIO 地址和目标存储桶

      const formData = new FormData();
      formData.append('file', this.file);

      try {
        const response = await axios.put(url, formData, {
          headers: {
            'Content-Type': this.file.type,
            'Authorization': `Bearer <your-access-token>` // 如果需要身份验证,请提供访问令牌
          },
          onUploadProgress: (progressEvent) => {
            this.progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
          }
        });
        console.log('上传成功:', response.data);
        this.progress = 0; // 重置进度
      } catch (err) {
        this.error = err.message;
        console.error('上传失败:', err);
      }
    },
  },
};
</script>

<style scoped>
/* 添加你的样式 */
</style>

minio-server-url、bucket-name、object-name、your-access-token这里根据自己minio上的设置自行替换

2. 修改

a. 图片破损问题

首先我通过上述的步骤实现了上传,但上传后的图片并不能正常显示,下载后打开显示图片破损
原因: 我们使用的是axios.put上传文件,put请求不需要使用formData,formData适合post请求上传数据,如果用put请求上传文件,文件的原始二进制内容应该直接作为请求体发送,而不是使用formData

这里我们将以下代码进行替换
const formData = new FormData();
formData.append(‘file’, this.file);
替换成
const formData=await this.file.arrayBuffer()

替换后,上传成功并在minio控制台可以预览出来图片,之前一直是加载图片,预览不了

b.拿不到文件链接

上传文件成功后,minio并没有返回他的链接,res.data=‘’, 因此这里我们需要自行构建

const response = await axios.put(url, formData, {
          headers: {
            'Content-Type': this.file.type,
            'Authorization': `Bearer <your-access-token>` // 如果需要身份验证,请提供访问令牌
          },
          onUploadProgress: (progressEvent) => {
            this.progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
          }
        });
        const fileUrl='http://<minio-server-url>/<bucket-name>/<object-name>'
        console.log('上传成功:', response.data);
c.文件名称

有时上传文件的名称可能会有重名,因此这里可以用时间戳进行一个拼接

 const fileName= file.name?`${Date.now()}_${file.name}`:`${Date.now()}_${file.raw.name}`

3.总结代码

以上是用type为file的input作为案例进行演示,如果用组件库,例如element-plus中的el-upload的话,文件内容会嵌套一层

<template>
  <el-upload :auto-upload="false" v-bind="$attrs" :disabled="disabled" v-model:file-list="fileList"
             :on-preview="handlePictureCardPreview" ref="upload">
    //这里的一些不涉及本文章的方法就不再下面的代码中进行赘述了,有需要请参考上篇文章
    <template #file="{file}">
      <div class="file-list-item cursor-pointer">
        <!-- 点击预览 -->
        <span @click="handlePictureCardPreview(file)" class="flex-1">{{ file.name }}</span>

        <!-- 显示进度条 -->
        <el-progress class="mt-2" :stroke-width="3" color="#409eff" v-if="file.status === 'ready' && file.percentage !== 0" :percentage="file.percentage" />

        <!-- 显示文件上传状态 -->
        <span v-if="file.status === 'success'" style="color: green;"><el-icon><CircleCheck /></el-icon></span>
        <span v-if="file.status === 'fail'" style="color: red;"><el-icon><CircleClose /></el-icon></span>

        <!-- 删除文件 -->
        <el-button class="w-[50px] h-[32px] border-[0] text-[20px] delete-btn" icon="close" @click="handleRemove(file)" />

      </div>
    </template>
  </el-upload>
  <el-dialog v-model="dialogVisible">
    <img class="w-full" :src="dialogImageUrl" alt="Preview Image" />
  </el-dialog>
</template>
 async sureUpload() {
      for (const file of this.fileList) {
        if (file.status !== 'ready') {
          continue
        }
        let res = await this.uploadEleFile(file)
        if (res) {
          file.url = res.link
          file.name=res.name
        }
      }
      this.$emit('update:modelValue', this.fileList.map(a => { return { url: a.url, name: a.name } }))
},
async uploadEleFile(file){
            if(!file) return
            const fileName= file.name?`${Date.now()}_${file.name}`:`${Date.now()}_${file.raw.name}`
            const url=`${server}:${post}/${bucket}/${fileName}`
            const fileData = await file.raw.arrayBuffer();

            return new Promise(async (resolve,reject)=>{
                let res;
                try {
                    res = await axios.put(url, fileData, {
                        headers: {
                            'Content-Type': file.raw.type,
                            'Authorization': `Bearer ${accessKey}`
                        },
                        // 监听上传进度
                        onUploadProgress: (progressEvent) => {
                            if (progressEvent.progress) {
                                const percentCompleted = Math.round(
                                    (progressEvent.loaded * 100) / progressEvent.total
                                );
                                // 更新进度
                                file.percentage = percentCompleted;
                            }
                        },
                    });
                    if(res.status===200){
                        file.status = 'success'
                        const url=`${server}:${post}/${bucket}/${fileName}`
                        resolve({link:url,name:file.name})
                    }
                    console.log('上传成功:', res);
                } catch (error) {
                    file.status = 'fail'
                    this.$message.error('上传失败,请重新选择素材进行上传')
                    reject(error)
                }
            })
        },
前端多线程上传minio可以通过Web Worker实现。Web Worker是一种在后台运行的JavaScript脚本,可以在不阻塞主线程的情况下进行耗时操作,如文件上传。以下是一个基本的前端多线程上传minio的示例代码: 1. 首先创建一个Worker对象,指定worker.js作为后台脚本: ```javascript var worker = new Worker("worker.js"); ``` 2. 在worker.js中编写上传代码,使用XMLHttpRequest或Fetch API上传文件。根据需求,可以将文件分割成多个小片并上传,或者使用断点上传技术实现断点续传。上传完成后,使用postMessage()方法将上传结果发送回主线程: ```javascript self.addEventListener('message', function(e) { var file = e.data.file; var xhr = new XMLHttpRequest(); xhr.open('PUT', 'http://minio.example.com/' + file.name, true); xhr.setRequestHeader('Content-Type', file.type); xhr.setRequestHeader('Content-Length', file.size); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status === 200 || xhr.status === 201) { self.postMessage({success: true, message: '上传成功'}); } else { self.postMessage({success: false, message: '上传失败'}); } } }; xhr.upload.onprogress = function(event) { var percent = Math.round((event.loaded / event.total) * 100); self.postMessage({progress: percent}); }; xhr.send(file); }, false); ``` 3. 在主线程中监听worker的message事件,接收上传结果并更新UI: ```javascript worker.addEventListener('message', function(e) { if (e.data.success) { alert('上传成功'); } else { alert('上传失败'); } }); ``` 4. 调用worker.postMessage()方法向worker发送上传任务: ```javascript var file = document.querySelector('#fileInput').files[0]; worker.postMessage({file: file}); ``` 需要注意的是,Web Worker只能在支持HTML5的浏览器中使用,且存在一定的安全性限制。上传到minio需要使用PUT请求,并设置正确的Content-Type和Content-Length头信息,否则上传会失败。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值