Skip to content

MinIO

TIP

MinIO 是一个对象存储服务。它非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件等,而一个对象文件可以是任意大小,从几kb到最大5T不等。而且它既支持服务端部署,也支持前端直连(通过SDK),本文主要介绍前端直连MinIO服务的详细过程。

MinIO相关文档

前端使用

  • 安装
bash
npm i minio -S
  • 文件操作通用方法 src/utils/minio.js
查看代码
js
const Minio = require('minio')
const stream = require('stream')

/**
 * @description    生成唯一文件名(规则:文件名+uid)
 * @param {string} name 初始文件名,带文件后缀
 * @param {string} uid  文件唯一标识
 */
function generateFileName(name, uid) {
  const spotIndex = name.lastIndexOf('.')
  const fileName = name.substring(0, spotIndex)
  const fileSuffix = name.substring(spotIndex)
  return `${fileName}_${uid}${fileSuffix}`
}

/**
 * @description    建立MinIO连接
 * @param {string} bucketName 存储桶名称
 */
export function createMinioClient(bucketName) {
  return new Promise((resolve, reject) => {
    /* 此服务是MinIO官方提供的测试服务,使用时可根据实际环境更改相关信息 */
    const minioClient = new Minio.Client({
      endPoint: 'play.min.io',
      port: 9000,
      useSSL: true,
      accessKey: 'Q3AM3UQ867SPQQA43P2F',
      secretKey: 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG'
    })

    minioClient.bucketExists(bucketName).then(res => {
      if (!res) {
        minioClient.makeBucket(bucketName, 'us-east-1', function(error) {
          if (error) {
            reject(error)
          }
          resolve(minioClient)
        })
      }
      resolve(minioClient)
    }).catch(err => {
      reject(err)
    })
  })
}

/**
 * @description    上传文件
 * @param {Object} minioClient minio实例
 * @param {Object} file        文件
 * @param {string} bucketName  存储桶
 */
export function minioUpload(minioClient, file, bucketName) {
  return new Promise((resolve, reject) => {
    const fileName = generateFileName(file.name, file.uid)
    const blob = new Blob([file], { type: file.type })
    const reader = new FileReader()
    reader.readAsArrayBuffer(blob)
    reader.onload = function(e) {
      const buffer = e.target.result
      const bufferStream = new stream.PassThrough()
      bufferStream.end(new Buffer(buffer))
      minioClient.putObject(bucketName, fileName, bufferStream, file.size, function(err, etag) {
        if (err) {
          reject(err)
        }
        resolve(etag)
      })
    }
  })
}

/**
 * @description    下载文件
 * @param {Object} minioClient minio实例
 * @param {string} bucketName  存储桶
 * @param {Object} file        文件
 * @param {string} fileUID     文件uid
 */
export function minioDownload(minioClient, bucketName, file, fileUID) {
  return new Promise((resolve, reject) => {
    const fileName = generateFileName(file.name, fileUID)
    minioClient.presignedGetObject(bucketName, fileName, 24 * 60 * 60, function(error, url) {
      if (error) {
        return reject(error)
      }
      resolve(url)
    })
  })
}

/**
 * @description    删除文件
 * @param {Object} minioClient minio实例
 * @param {string} bucketName  存储桶
 * @param {Object} file        文件
 * @param {string} fileUID     文件uid
 */
export function minioRemove(minioClient, bucketName, file, fileUID) {
  return new Promise((resolve, reject) => {
    const fileName = generateFileName(file.name, fileUID)
    minioClient.removeObject(bucketName, fileName, function(err) {
      if (err) {
        reject(err)
      }
      resolve(true)
    })
  })
}
  • Vue中使用 (此处使用Element中的上传组件)
vue
<template>
  <div>
    <el-upload
      action=""
      multiple
      :auto-upload="false"
      :show-file-list="true"
      :file-list="fileList"
      :on-change="(f, list) => handleFileChange(f, list)"
      :on-preview="handleFilePreview"
      :on-remove="(f, list) => handleFileRemove(f, list)"
    >
      <el-button type="primary" icon="el-icon-upload">选择附件</el-button>
    </el-upload>
  </div>
</template>

<script>
import { createMinioClient, minioUpload, minioDownload, minioRemove } from '@/utils/minio'

export default {
  data() {
    return {
      loading: false,
      minioClient: null // MinIO实例
    }
  },
  created() {
    // 创建MinIO实例
    this.loading = true
    createMinioClient().then(res => {
      this.minioClient = res
    }).finally(() => {
      this.loading = false
    })
  },
  methods: {
    handleFileChange(file, fileList) {
      if (!this.minioClient) return
      minioUpload(this.minioClient, file.raw, 'xx').then(res => {
        // success & do something
      })
    },

    handleFilePreview(file) {
      minioDownload(this.minioClient, 'xx', file, file.uid).then(url => {
        // do something
        // 下载文件
        window.open(url, '_self')
      })
    },

    handleFileRemove(file) {
      minioRemove(this.minioClient, 'xx', file, file.uid).then(res => {
        // do something
      })
    }
  }
}
</script>

Updated at: