需求
上傳視訊到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;
}
複製程式碼