前言
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 也可以達到一樣的效果