一种Flutter上传图片到阿里OSS的方式
折腾了几天的flutter上传图片到阿里云,连通过flutter通道调用原生都写完了,老大却说一定有直接使用flutter的方式,只好再继续研究了。
扒了阿里云上传安卓SDK的源码,又用抓包的方式在flutter这边获取更多的信息(否则的话只能拿到403等,根本没有有用的信息),总算是搞定了。
首先引入包crypto: ^2.1.4
dio: ^4.0.6
import 'dart:collection';
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart';
import 'package:intl/intl.dart';
const String bucket = '替换成你的bucket';
String host = "$bucket.oss-cn-beijing.aliyuncs.com"; //写入你对应的地址
String url = 'https://$bucket.oss-cn-beijing.aliyuncs.com';
Future<String> ossUploadImage(Uint8List imageData,
{required String fileType, String? directory = "community"}) async {
//命名
String timeStr = DateFormat("yyyyMMdd", 'en').format(DateTime.now());
String pathName = "img/$directory/app$timeStr${getRandom(12)}.$fileType";
//第一步 从服务器获取stsinfo
Dio dio = Dio();
Map params = {}; //参数自理
Response e = await dio.get("baseUrl/oss/getStsInfo", //地址自理
queryParameters: Map.from(params));
Map<String, dynamic> responseData = jsonDecode(e.data);
String statusCode = responseData["StatusCode"];
String accessKeyId = responseData["AccessKeyId"];
String accessKeySecret = responseData["AccessKeySecret"];
String securityToken = responseData["SecurityToken"];
String date = getGMTDateString();
if (statusCode == "200") {
String contentType = 'image/$fileType';
//签名相关
//请求头
SplayTreeMap<String, String> treeMap = SplayTreeMap();
treeMap["Content-Type".toLowerCase()] = contentType.trim();
treeMap["Content-MD5".toLowerCase()] = "";
treeMap["Date".toLowerCase()] = date.trim();
treeMap["x-oss-security-token".toLowerCase()] = securityToken.trim();
String headString = "PUT\n";
treeMap.forEach((key, value) {
if (key.startsWith("x-oss-")) {
headString += key;
headString += ':';
headString += value;
} else {
headString += value;
}
headString += '\n';
});
String contentString = "/$bucket/$pathName";
String contentToSign = headString + contentString;
List<int> key = utf8.encode(accessKeySecret);
List<int> data = utf8.encode(contentToSign);
var signaturePre = Hmac(sha1, key).convert(data).bytes;
//最后一步,将上述所得进行base64 编码
String signature = base64.encode(signaturePre);
String signatureA = "OSS " + accessKeyId + ":" + signature;
Dio dio = Dio();
dio.options.responseType = ResponseType.plain;
dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {
options.headers["Authorization"] = signatureA;
options.headers["Host"] = host;
options.headers["x-oss-security-token"] = securityToken;
options.contentType = contentType;
options.headers["date"] = date;
handler.next(options);
}));
try {
// 发送请求
var resultUrl = url + "/$pathName";
//必须转成这个类型才可以
Stream<List<int>> stream = Stream.value(imageData);
var rep = await dio.put(resultUrl, data: stream);
// 成功后返回文件访问路径
return "替换成你的base地址/$pathName";
} catch (e) {
return '';
}
}
return "";
}
String getRandom(int num) {
String alphabet = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
String left = "";
for (var i = 0; i < num; i++) {
left = left + alphabet[Random().nextInt(alphabet.length)];
}
return left;
}
//这个时间要注意
String getGMTDateString() {
var date = DateTime.now();
date = date.subtract(const Duration(hours: 8));
return DateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", 'en').format(date);
}