什么是MinIO?
MinIO 是一款高性能、分布式的对象存储系统. 它是一款软件产品, 可以100%的运行在标准硬件。即X86等低成本机器也能够很好的运行MinIO。
本地Docker部署测试服务器
docker pull bitnami/minio:latest # MINIO_ROOT_USER最少3个字符# MINIO_ROOT_PASSWORD最少8个字符# 第一次运行的时候,服务会自动关闭,手动再次启动就可以正常运行了.docker run -itd \ --name minio-server \ -p9000:9000 \ -p9001:9001 \ --envMINIO_ROOT_USER="root" \ --envMINIO_ROOT_PASSWORD="123456789" \ --envMINIO_DEFAULT_BUCKETS='images' \ --envMINIO_FORCE_NEW_KEYS="yes" \ --envBITNAMI_DEBUG=true \ bitnami/minio:latest
上传的API
它有3个API可供调用:
- putObject 从流上传
- fPutObject 从文件上传
- presignedPutObject 提供一个临时的上传链接以供上传
使用1和2的方式的话,在前端需要暴露出连接MinIO的访问密钥,很不安全,而且官方的Js客户端压根就没想过开放给浏览器.
而3的话,可以由服务端生成一个临时的上传链接提供给前端上传之用,而无需要暴露访问MinIO的密钥,非常的安全,我采用的是第三种方式.
第三种方式,官方有一篇文章: Upload Files Using Pre-signed URLs
TypeScript实现
在TypeScript下,我们可用的有三种方式实现文件上传:
需要注意的是: 事实上,后两种API都是封装的XMLHttpRequest.
1. XMLHttpRequest
functionxhrUploadFile(file: File, url: string) { constxhr=newXMLHttpRequest(); xhr.open('PUT', url, true); xhr.send(file); xhr.onload= () => { if (xhr.status===200) { console.log(`${file.name}上传成功`); } else { console.error(`${file.name}上传失败`); } }; }
2. Fetch API
functionfetchUploadFile(file: File, url: string) { fetch(url, { method: 'PUT', body: file, }) .then((response) => { console.log(`${file.name}上传成功`, response); }) .catch((error) => { console.error(`${file.name}上传失败`, error); }); }
3. Axios
functionaxiosUploadFile(file: File, url: string) { constinstance=axios.create(); instance .put(url, file, { headers: { 'Content-Type': file.type, }, }) .then(function (response) { console.log(`${file.name}上传成功`, response); }) .catch(function (error) { console.error(`${file.name}上传失败`, error); }); }
从后端获取临时上传链接
functionretrieveNewURL(file: File, cb: (file: File, url: string) =>void) { consturl=`http://localhost:8080/presignedUrl/${file.name}`; axios.get(url) .then(function (response) { cb(file, response.data.data.url); }) .catch(function (error) { console.error(error); }); }
上传文件
functiononXhrUploadFile(file?: File) { console.log('onXhrUploadFile', file); if (file) { retrieveNewURL(file, (file, url) => { xhrUploadFile(file, url); }); } }
踩过的坑
1. presignedPutObject
方式上传提交的方法必须得是PUT
我试过了用POST
去上传文件,但是显然的是:我失败了.必须得用PUT
去上传.
2. 直接发送File
即可
看了不少文章都是这么干的: 构造一个FormData
,然后把文件打进去,如果用putObject
和fPutObject
这两种方式上传,这是没问题的,但是使用presignedPutObject
则是不行的,直接发送File
就可以了.
fileUpload(file) { consturl='http://example.com/file-upload'; constformData=newFormData(); formData.append('file', file) constconfig= { headers: { 'content-type': 'multipart/form-data' } } returnpost(url, formData,config) }
如果使用以上的方式上传,文件头会被插入一段数据,看起来像是这样子的:
------WebKitFormBoundaryaym16ehT29q60rUx Content-Disposition: form-data; name="file"; filename="webfonts.zip" Content-Type: application/zip
它是遵照了 rfc1867 定义的协议.
3. 使用Axios
上传的时候,需要自己把Content-Type
填写成为file.type
直接使用XMLHttpRequest
和Fetch API
都会自动填写成为文件真实的Content-Type
.而Axios
则不会,需要自己填写进去,或许是我不会使用Axios
,但是这是一个需要注意的地方,否则在MinIO里边的Content-Type
会被填写成为Axios
默认的Content-Type
,或者是你自己指定的.
示例代码
Github: https://github.com/tx7do/minio-typescript-example
- 后端采用go+gin实现,用于调用MinIO的API
presignedPutObject
获取临时上传Url. - 前端有React和Vue的实现,要实现进度条和多文件上传也是容易的.