前言

MinIO提供高性能、S3兼容的对象存储。MinIO是一个基于Go语言的对象存储服务。它实现了大部分亚马逊S3云存储服务接口,可以看做是是S3的开源版本,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。区别于分布式存储系统,MinIO的特色在于简单、轻量级,对开发者友好,认为存储应该是一个开发问题而不是一个运维问题。

问题背景

项目需要上传大文件,既然是大文件,如果一次性进行读取发送、接收都是不可取的,很容易导致内存问题。所以对于大文件上传,就一定要实现切片上传、断点续传。如果自己实现相对比较麻烦,但好消息是正好我们的后台文件服务使用了开源的MinIO作为对象存储服务,MinIO也提供了 JavaScript Client SDK ,但当我看到文档正准备一顿操作时就遇到了问题:ReferenceError: require is not defined

问题分析

分析报错后发现原因是我们的项目使用的是vite进行构建,vite默认使用es6标准的 import 的导入方式,不支持require引入。所以,需要解决的问题就是如何将MinIO通过import的方式导入到项目中。

解决思路

  1. 尝试将 require 写法直接改为 import 写法,实践结果失败,原因是MinIO又不支持 import 的导入方式。
  2. 既然vite不支持require,但webpack是支持的,可以将MinIO先通过require导入到一个使用webpack构建的项目,再将此项目引入到我们自己的项目,实践结果成功。

最后在gitee上找到一个大佬上传的组件得以解决:https://gitee.com/zheyiw/minio-js-m

使用流程

安装:yarn add minio-js

在Vue3(vite)中使用

大佬提供的方法目前只有初始化上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<template>
<div id="nav">
<p>vite中import使用miniojs上传文件</p>
<input ref="input" type="file" @change="handleFiles" />
</div>
</template>
<script lang="ts">
import { initMinio, putObject } from 'minio-js'

export default {
methods: {
handleFiles(event: any) {
var f = event.target.files[0]
let reader = new FileReader()
reader.readAsArrayBuffer(f)
reader.onload = function (e: any) {
let res = e.target.result //ArrayBuffer
//先初始化
initMinio({
endPoint: '192.168.2.98',
port: 9002,
useSSL: false,
accessKey: 'admin',
secretKey: '12345678',
})
//再上传
putObject('act', res, f.name, function (err, data) {
if (err) console.log(err)
else {
console.log('上传完成')
}
})
}
},
},
}
</script>

好在大佬抛出了MinIO的对象,可以自行引用调取官网的MinIO方法

比如下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Minio } from 'minio-js'

var fileUrl = '';
const minioClient = new Minio.Client({
endPoint: 'play.min.io', // 地址
port: 9000, // 端口号,若地址为类似test.minio.com,就不必写端口号
useSSL: false, // 是否使用ssl
accessKey: '登录的accessKey', // 登录的accessKey
secretKey: 'secretKey', // secretKey
sessionToken: 'token',
region: 'zh'
});

minioClient.presignedUrl('GET', 'bucket', 'fileKey', 24 * 60 * 60, function (err, presignedUrl) {
if (err) return console.log(err)
fileUrl = presignedUrl;
})

在Html中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<html>
<head>
<title>MinioJs</title>
</head>
<body>
<div id="root">MinioJs</div>
<script type="text/javascript" src="./MinioJs.js"></script>
<script
type="text/javascript"
src="http://code.jquery.com/jquery-1.10.2.min.js"
></script>
<div id="nav">
<p>Minio文件上传:</p>
<form id="form"><input type="file" name="file" id="file" /><br /></form>
</div>
<script type="text/javascript">
$(function () {
form.reset(); //清除浏览器记录的上次记录
var file;
$(form).on("change", "#file", function (e) {
console.log(this.value); //文件路径
console.log(this.files[0].name); //文件名

//把文件以ArrayBuffer的形式读取后给Minio上传
var f = this.files[0];
let reader = new FileReader();
reader.readAsArrayBuffer(f);
reader.onload = function (e) {
let res = e.target.result; //ArrayBuffer
//先初始化
MinioJs.initMinio({
endPoint: "192.168.2.98",
port: 9002,
useSSL: false,
accessKey: "admin",
secretKey: "12345678",
});
//再上传
MinioJs.putObject("bucket1", res, f.name, function (err, data) {
if (err) console.log(err)
else {
console.log('上传完成')
}
});
};
});
});
</script>
</body>
</html>

在Vue项目中以直接引入Js的方式使用

把MinioJs.js放在public目录下面,在index.html中引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
<script type="text/javascript" src="config.js"></script>
<script type="text/javascript" src="MinioJs.js"></script>
</head>

<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>

</html>

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<template>
<div id="nav">
<p>MinioJs上传文件:</p>
<input ref="input" type="file" @change="handleFiles" />
</div>
</template>
<script lang="ts">
declare const MinioJs: any //定义

export default {
methods: {
handleFiles(event: any) {
var f = event.target.files[0]
let reader = new FileReader()
reader.readAsArrayBuffer(f)
reader.onload = function (e: any) {
let res = e.target.result //ArrayBuffer
//先初始化
MinioJs.initMinio({
endPoint: '192.168.2.98',
port: 9002,
useSSL: false,
accessKey: 'admin',
secretKey: '12345678',
})
//再上传
MinioJs.putObject("bucket1", res, f.name, function (err, data) {
if (err) console.log(err)
else {
console.log('上传完成')
}
});
}
},
},
}
</script>

ps:因作者能力有限,有错误的地方请见谅

  • 喜欢这篇文章的话可以用快捷键 Ctrl + D 来收藏本页
× 请我吃糖~
打赏二维码