“不就是上传一张图片吗?能有多难?” 在我需要通过api在flutter中上传我的博客图片到阿里云的时候,我轻视地想着。
然后时间不知不觉就跳到了两天后~~
前言:为什么花了么长的时间? 一部分花在了找文档看文档,找可行方案。
另一部分花在了签名尝试。(签名校验真复杂)
再一部分花在了putObject和postObject方法的反复尝试。
阳光总在风雨后,曲折的道路阿终于还是成功了~
一.找方案踩坑 第一步,首先去官网 找阿里云oss有没有相关的可用sdk。 到网站找一找,不出意料,flutter这种还没啥人用的小玩意,这个时间点阿里还是没有出sdk。
第二步,找到api请求上传的签名校验方式以及参数api 签名校验官网说明
Header添加签名的具体生成方式说明
Api 地址:https://oss-example.oss-cn-hangzhou.aliyuncs.com
oss-example使用自己的bucket名称代替
第三步,找到可以成功的图片上传api 我最初找到的是putObject方法(文档 ),在参考官方的java代码,终于在header添加可用的签名后,却老是报错xml 参数错误啥的。因为我明明没有传xml参数,只是put
了image/jpg
所以十分不解,一脸困惑。
最终尝试使用postObject(文档 )方法成功了。
二.可行的详细路线
第一反应,如果是开发的非flutter 平台可以尝试找找官方sdk
sdk列表链接
官方说明的伪代码:
1 2 3 4 5 6 7 8 9 ///Authorization字段计算的方法 Authorization = "OSS " + AccessKeyId + ":" + Signature Signature = base64(hmac-sha1(AccessKeySecret, VERB + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Date + "\n" + CanonicalizedOSSHeaders + CanonicalizedResource))
实际编写出来的dart代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class OssUtils { static var f = DateFormat('EEE, dd MMM yyyy HH:mm:ss' ); static String buildSignature(String httpMethod, String resourcePath, RequestOptions request) { var Date = f.format(DateTime .now().toUtc()) + " GMT" ; request.headers['Date' ]=Date; var CanonicalizedOSSHeaders = buildCanonicalizedOSSHeaders(request); var CanonicalizedResource = resourcePath; final headers = request.headers.map((key, value) => MapEntry(key.toLowerCase(), value)); var string = StringBuffer ()..writeln(httpMethod); if (headers.containsKey(HttpHeaders.contentMD5Header)) { string.write(headers[HttpHeaders.contentMD5Header]); } string.writeln(); if (headers.containsKey(HttpHeaders.contentTypeHeader)) { string.write(headers[HttpHeaders.contentTypeHeader]); } string.writeln(); string ..writeln(Date) ..write(CanonicalizedOSSHeaders) ..write(CanonicalizedResource); var Signature = base64.encode(Hmac(sha1, AccessKeySecret.toBytes()).convert(string.toString().toBytes()).bytes); var Authorization = "OSS " + AccessKeyId + ":" + Signature; return Authorization; } static String buildCanonicalizedOSSHeaders(RequestOptions request) { final canonicalOssHeadersString = StringBuffer (); final headers = request.headers; final canonicalizedOssHeadersToSign = SplayTreeMap<String , String >(); headers.forEach((key, value) { String lowerKey = key.toLowerCase(); if (lowerKey.startsWith("x-oss-" )) { canonicalizedOssHeadersToSign[lowerKey] = value.toString().trim(); } }); canonicalizedOssHeadersToSign.forEach((key, value) { canonicalOssHeadersString ..write(key) ..write(':' ) ..writeln(value); }); return canonicalOssHeadersString.toString(); } }
最后在dio拦截器中调用生成签名方法,添加签名到Headers中
1 2 3 4 5 6 7 _ossdio!.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { var Authorization = OssUtils.buildSignature(options.method, "/guuguohome/" , options); options.headers["Authorization" ] = Authorization; handler.next(options); }, onResponse: _onResponse));
第三接下来,使用 postObject 上传图片(官网文档 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 Future<String > uploadToOss(File image) async { var host = "${bucket} .oss-cn-hangzhou.aliyuncs.com" ; var url = "https://${host} " ; var fileName = path.split(image.path).last; var policyData = { "expiration" : "2314-12-01T12:00:00.000Z" , "conditions" : [ {"bucket" : bucket}, ] }; var policy = base64.encode(json.encode(policyData).toBytes()); var signature = base64.encode(Hmac(sha1, AccessKeySecret.toBytes()).convert(policy.toBytes()).bytes); final data = FormData.fromMap({ "file" : await MultipartFile.fromFile( image.path, filename: fileName, ), "key" : fileName, "policy" : policy, "Signature" : signature, "OSSAccessKeyId" : AccessKeyId, }); Options? options = Options(headers: { "x-oss-storage-class" : "IA" , "Host" : host, "Content-Encoding" : "utf-8" , }); final res = await getOssDio().post(url, options: options, data: data); return url + "/" + fileName; }
去阿里云oss控制台 可以看到 bucket中已经多出了一个图片文件。
可喜可贺,可喜可贺
三.查看图片 上传图片后,自然需要拿到访问图片的url链接才能访问。
这时候有两种情况
第一种很简单:公共读的bucket
图片要对外展示, 保证 bucket 权限设置为公共读
在公共读权限下,查看图片就变得简单,只需要使用key拼接好url链接就行了。
1 2 3 var url="https://${bucket} .oss-cn-hangzhou.aliyuncs.com/${objectkey} "
看文档看文档看文档
四.结尾
“不就是上传一张图片吗?能有多难?”
看着终于成功上传的图片,我小声呢喃。