flutter直接上传文件到阿里云oss
作者:阳春boy
上传视频到oss,之前是走后端上传到oss,会有一个问题就是我要先上传给后端,后端再上传给oss就会导致上传多次,消耗时间过长影响用户体验,所以我参考文档写了直接上传到阿里云oss获取到文件访问路径。
代码实现
以下是我写的一个上传oss的类,只需要替换ossAccessKeyId, ossAccessKeySecret, bucket, url, expiration这几个参数就可以直接实现上传
import 'dart:convert'; import 'dart:io'; import 'dart:math'; import 'package:crypto/crypto.dart'; import 'package:dio/dio.dart'; class UploadOss { static String ossAccessKeyId = 'ossAccessKeyId'; static String ossAccessKeySecret = 'ossAccessKeySecret'; // oss设置的bucket的名字 static String bucket = 'bucketName'; // 发送请求的url,根据你自己设置的是哪个城市的 static String url = 'https://$bucket.oss-cn-hangzhou.aliyuncs.com'; // 过期时间 static String expiration = '2025-01-01T12:00:00.000Z'; /** * @params file 要上传的文件对象 * @params rootDir 阿里云oss设置的根目录文件夹名字 * @param fileType 文件类型例如jpg,mp4等 * @param callback 回调函数我这里用于传cancelToken,方便后期关闭请求 * @param onSendProgress 上传的进度事件 */ static Future<String> upload({ File file , String rootDir = 'moment', String fileType, Function callback, Function onSendProgress}) async { String policyText = '{"expiration": "$expiration","conditions": [{"bucket": "$bucket" },["content-length-range", 0, 1048576000]]}'; // 获取签名 String signature = getSignature(policyText); BaseOptions options = new BaseOptions(); options.responseType = ResponseType.plain; //创建dio对象 Dio dio = new Dio(options); // 生成oss的路径和文件名我这里目前设置的是moment/20201229/test.mp4 String pathName = '$rootDir/${getDate()}/${getRandom(12)}.${fileType == null ? getFileType(file.path) : fileType}'; // 请求参数的form对象 FormData data = new FormData.fromMap({ 'key': pathName, 'policy': getSplicyBase64(policyText), 'OSSAccessKeyId': ossAccessKeyId, 'success_action_status': '200', //让服务端返回200,不然,默认会返回204 'signature': signature, 'contentType': 'multipart/form-data', 'file': MultipartFile.fromFileSync(file.path), }); Response response; CancelToken uploadCancelToken = CancelToken(); callback ?? callback(uploadCancelToken); try { // 发送请求 response = await dio.post(url, data: data, cancelToken: uploadCancelToken, onSendProgress: (int count, int data) { onSendProgress(count, data); }); // 成功后返回文件访问路径 return '$url/$pathName'; } catch(e) { throw(e.message); } } /* * 生成固定长度的随机字符串 * */ static String getRandom(int num) { String alphabet = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'; String left = ''; for (var i = 0; i < num; i++) { // right = right + (min + (Random().nextInt(max - min))).toString(); left = left + alphabet[Random().nextInt(alphabet.length)]; } return left; } /* * 根据图片本地路径获取图片名称 * */ static String getImageNameByPath(String filePath) { // ignore: null_aware_before_operator return filePath?.substring(filePath?.lastIndexOf("/")+1,filePath?.length); } /** * 获取文件类型 */ static String getFileType(String path) { print(path); List<String> array = path.split('.'); return array[array.length -1]; } /// 获取日期 static String getDate() { DateTime now = DateTime.now(); return '${now.year}${now.month}${now.day}'; } // 获取plice的base64 static getSplicyBase64(String policyText) { //进行utf8编码 List<int> policyText_utf8 = utf8.encode(policyText); //进行base64编码 String policy_base64 = base64.encode(policyText_utf8); return policy_base64; } /// 获取签名 static String getSignature(String policyText) { //进行utf8编码 List<int> policyText_utf8 = utf8.encode(policyText); //进行base64编码 String policy_base64 = base64.encode(policyText_utf8); //再次进行utf8编码 List<int> policy = utf8.encode(policy_base64); //进行utf8 编码 List<int> key = utf8.encode(ossAccessKeySecret); //通过hmac,使用sha1进行加密 List<int> signature_pre = Hmac(sha1, key).convert(policy).bytes; //最后一步,将上述所得进行base64 编码 String signature = base64.encode(signature_pre); return signature; } }
调用上传的例子
其他参事自己根据自己情况上传
Future<String> uploadFile(File file, { Function onSendProgress, Function callback}) async { final String url = await UploadOss.upload(file: file, onSendProgress: onSendProgress, callback: callback); return url; }
另一种方法
目前阿里没有针对Flutter有官方SDK可集成, 但是有人对Flutter的上传有封装库https://pub.dev/packages/aly_oss#-example-tab-, 所以我们只能通过post提交PostObject的形式来上传;
准备工作:
1、获取OSS凭证地址(your oss_sts_server), 通知get直接获取static String ossServerUrl = 'http://.../sts-server/sts.php';
2、上传的存储地址(桶名):static String ossEndPointCdn = '<your endpointcdn>';
// 通过ossServerUrl直接get获取到如下数据 { "StatusCode": 200, "AccessKeyId": "STS.NSsrKZes4cqm.....", "AccessKeySecret": "7eGnLZaEFsRCGYJAnrtdE9n.....", "Expiration": "2020-04-08T03:44:21Z", "SecurityToken": "CAISlQJ1q6Ft5B2y....." } //表单需要的参数: AccessKeyId、AccessKeySecret、SecurityToken; FormData formdata = new FormData.from({ //文件名,随意 'Filename': OssUtil.instance.getImageName(filePath), //"可以填写文件夹名(对应于oss服务中的文件夹)/" + fileName 'key': uploadName,//上传后的文件名 'policy': OssUtil.policy, //Bucket 拥有者的AccessKeyId。 'OSSAccessKeyId': data['AccessKeyId'], //让服务端返回200,不然,默认会返回204 'success_action_status': '200', 'signature': OssUtil.instance.getSignature(data['AccessKeySecret']), //临时用户授权时必须,需要携带后台返回的security-token 'x-oss-security-token': data['SecurityToken'], 'file': new UploadFileInfo( file, OssUtil.instance.getImageNameByPath(filePath)) //必须放在参数最后 }); //然后通过存储地址直接把表单(formdata)上传上去; Dio dio=Dio(); dio.options.responseType=ResponseType.plain; Response response=awaitdio.post(<ossEndPointCdn>,data:formData); ......
tips: 上传成功后图片地址 imageUrl = ossEndPointCdn + '/' + uploadName;
给一个工具类
import 'dart:convert'; import 'package:crypto/crypto.dart'; import 'dart:math'; class OssUtil { 获取 //验证文本域 static String _policyText = '{"expiration": "2069-05-22T03:15:00.000Z","conditions": [["content-length-range", 0, 1048576000]]}';//UTC时间+8=北京时间 //进行utf8编码 // ignore: non_constant_identifier_names static List<int> _policyText_utf8 = utf8.encode(_policyText); //进行base64编码 static String policy= base64.encode(_policyText_utf8); //再次进行utf8编码 // ignore: non_constant_identifier_names static List<int> _policy_utf8 = utf8.encode(policy); // 工厂模式 factory OssUtil() => _getInstance(); static OssUtil get instance => _getInstance(); static OssUtil _instance; OssUtil._internal(); static OssUtil _getInstance() { if (_instance == null) { _instance = new OssUtil._internal(); } return _instance; } /* *获取signature签名参数 */ String getSignature(String _accessKeySecret){ //进行utf8 编码 // ignore: non_constant_identifier_names List<int> AccessKeySecretUtf8 = utf8.encode(_accessKeySecret); //通过hmac,使用sha1进行加密 List<int> signaturePre = new Hmac(sha1, AccessKeySecretUtf8).convert(_policy_utf8).bytes; //最后一步,将上述所得进行base64 编码 String signature = base64.encode(signaturePre); return signature; } // ignore: slash_for_doc_comments /** * 生成上传上传图片的名称 ,获得的格式:photo/20171027175940_oCiobK * 可以定义上传的路径uploadPath(Oss中保存文件夹的名称) * @param uploadPath 上传的路径 如:/photo * @return photo/20171027175940_oCiobK */ String getImageUploadName(String uploadPath,String filePath) { String imageMame = ""; var timestamp = new DateTime.now().millisecondsSinceEpoch; imageMame =timestamp.toString()+"_"+getRandom(6); if(uploadPath!=null&&uploadPath.isNotEmpty){ imageMame=uploadPath+"/"+imageMame; } String imageType=filePath?.substring(filePath?.lastIndexOf("."),filePath?.length); return imageMame+imageType; } String getImageName(String filePath) { String imageMame = ""; var timestamp = new DateTime.now().millisecondsSinceEpoch; imageMame =timestamp.toString()+"_"+getRandom(6); String imageType=filePath?.substring(filePath?.lastIndexOf("."),filePath?.length); return imageMame+imageType; } /* * 生成固定长度的随机字符串 * */ String getRandom(int num) { String alphabet = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'; String left = ''; for (var i = 0; i < num; i++) { // right = right + (min + (Random().nextInt(max - min))).toString(); left = left + alphabet[Random().nextInt(alphabet.length)]; } return left; } /* * 根据图片本地路径获取图片名称 * */ String getImageNameByPath(String filePath) { // ignore: null_aware_before_operator return filePath?.substring(filePath?.lastIndexOf("/")+1,filePath?.length); } }
以上就是flutter直接上传文件到阿里云oss的实现步骤的详细内容,更多关于flutter 上传文件到阿里云oss的资料请关注脚本之家其它相关文章!