前言
Minio作为很出名的文件存储服务, 因其开源和使用便利等优点被很多公司采用
Minio的官网 点我
在使用中, 我发现在Minio中存储图片文件时, 会因为图片文件的特性, 当你生成分享链接时, 通过链接访问出来的并不是下载流而是直接打开, 本文介绍原因和解决办法
正文
原因
浏览器根据响应的 Content-Type 来确定文件格式, 当我们上传一个图片到 minio 时, 默认时会将图片自动识别, 其 Content-Type 为 image/png 于是当我们访问时则会在浏览器直接打开
而我们直接上传一个文件, 再通过链接进入发现其 Content-Type 为 application/octet-stream, 此时可以正常下载
根据资料显示确实如此
所以如果我们在图片上传如果能将其修改为文件而不是图片即可解决问题
我们查看 Minio 的 Golang客户端文档
找到其上传文件的文档, 发现方法中有一个参数为 opts, 其为 minio.PutObjectOptions 类型, 其中有一个参数为 opts.ContentType
我们在代码中实现为
// UploadToFDB upload to FDB
func UploadToFDB(object, file string) error {
opts := minio.PutObjectOptions{
ContentType: "application/octet-stream",
}
_, err := FDB.FPutObject(ctx, tools.EnvConfig.Minio.Bucket, object, file, opts)
if err != nil {
tools.Log.Error("upload to FDB error", zap.Error(err))
return err
}
return nil
}
测试发现上传到Minio后识别为文件了, 而且生成的链接可正常下载
而后我又发现其实在生成分享链接时也可以指定 response 的头, 如果将其强制指定为 application/octet-stream 应该也可以解决问题
我们查看文档的 PresignedGetObject 部分, 其参数中有一个 reqParams 可以指定 response-content-type 参数, 所以我们可以修改生成分享链接的代码为
// ShareFromFDB share
func ShareFromFDB(object string) (string, error) {
reqParams := make(url.Values)
reqParams.Set("response-content-type", "application/octet-stream")
if _, err := FDB.StatObject(ctx, tools.EnvConfig.Minio.Bucket, object, minio.StatObjectOptions{}); err != nil {
return "", err
}
url, err := FDB.PresignedGetObject(ctx, tools.EnvConfig.Minio.Bucket, object, time.Second*60*60*24*7, reqParams)
if err != nil {
tools.Log.Error("share From FDB error", zap.Error(err))
return "", err
}
return url.String(), nil
}
经测试此方法无需在上传时指定 Content-Type 也可以达到一样的效果