小程序前端上传文件不建议直接引用minio的js npm包,一来是这个包本身较大,会影响小程序的体积,二来是ak sk需要放到前端存储,不够安全,因此建议通过请求后端拿到签名数据后上传。
由于小程序的uploadFile仅支持POST请求(估计以后也不会支持PUT了),因此只能使用minio的PresignedPostPolicy方法返回签名后的formData,然后再放到小程序的uploadFile方法的formData参数中
后端 .net
安装minio nuget包
接口返回dto
public class UploadInfo { public string Key { get; set; } public string Url { get; set; } public Dictionary<string, string> FormData { get; set; } }
多个key进行预签名, 注意new MinioClient的第一个参数是minio的服务器地址,不能有http://或https://, 如果是https则需要new 之后再调用.WithSSL(),参见官方文档。 当然最佳实践还是要将minioClient对象通过依赖注入管理,minio相关配置通过IConfiguration(appsettings.json)来管理。
public async Task<UploadInfo[]> PresignedPostPolicyAsync(string[] keys) { string bucket = "myBucket"; var minioClient = new MinioClient("myminio.com:9000", "ak", "sk" ); var result = new UploadInfo[keys.Length]; for (int i = 0; i < keys.Length; i++) { var policy = new PostPolicy(); policy.SetKey(keys[i]); policy.SetBucket(bucket); policy.SetExpires(DateTime.UtcNow.AddHours(2));//设置策略过期时间 Tuple<string, Dictionary<string, string>> data = await minioClient.PresignedPostPolicyAsync(policy); result[i] = new UploadInfo { Key = keys[i], Url = $"{data.Item1}{bucket}/{keys[i]}", FormData = data.Item2, }; } return result; }
后端 java
dto
import java.util.Map; import lombok.Data; @Data public class Upload { private String key; private String url; private Map<String, String> formData; }
多个key进行预签名, 和.net sdk不一样的地方在于minio 服务器地址需要加上http, 还有可以设置上传条件,如 addEqualsCondition("key", key),表示key必须为对应的值, addStartsWithCondition("content-type","image/") 表示content-type必须以image/开头,也就是只能上传图片。
public List<Upload> uploadFiles(String[] keys) throws IOException, NoSuchAlgorithmException, InvalidKeyException { List<Upload> uploads = new ArrayList<>(); String bucket = "myBucket"; String endPoint = "http://myminio.com:9000"; try { MinioClient minioClient = MinioClient.builder() .endpoint(endPoint) .credentials("ak", "sk") .build();for (int i = 0; i < jsonArray.size(); i++) { Upload upload = new Upload(); String key = keys[i]; PostPolicy policy = new PostPolicy(bucket, ZonedDateTime.now().plusHours(2)); policy.addEqualsCondition("key", key); Map<String, String> formData = minioClient.getPresignedPostFormData(policy); String url = endPoint + "/" + bucket +"/" + key; upload.setKey(key); upload.setUrl(url); upload.setFormData(formData); uploads.add(upload); } }catch (MinioException e) { System.out.println("Error occurred: " + e); } return uploads; }
小程序
Taro代码如下,如果是原生微信小程序则把Taro换为wx即可。 注意uploadFile参数里 name需要设置为file, formData里设置key为policy签名的key。 上传成功minio会返回204
1 let minioUrl = 'https://myminio.com:9000' 2 let minioPresignUrl = 'https://myminio.com:8000/files/presign'; 3 Taro.chooseImage({ 4 count: 1, 5 sizeType: ["original", "compressed"], 6 sourceType: ["album", "camera"], 7 success: async res=>{ 8 let result = await Taro.request({url: minioPresignUrl, data: {keys:[res.tempFilePaths[0]]}}); 9 result.data.data.forEach(f => { 10 f.formData.key = f.key; 11 Taro.uploadFile({ 12 filePath:res.tempFilePaths[0] , 13 name: "file", 14 url: minioUrl, 15 formData: f.formData, 16 success: r => { 17 if (r.statusCode === 204) { 18 console.log('上传成功'); 19 } 20 } 21 }); 22 }) 23 } 24 })