Flutter 使用api 上传图片到阿里云OSS

"不就是上传一张图片吗?能有多难?"

在我需要通过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参数,只是putimage/jpg所以十分不解,一脸困惑。

最终尝试使用postObject(****文档****)方法成功了。

二.可行的详细路线

  • 第一反应,如果是开发的非flutter 平台可以尝试找找官方sdk

sdk列表链接

  • 第二步骤,然后开始参照官方签名文档开始签名。

官方说明的伪代码:

///Authorization字段计算的方法
Authorization = "OSS " + AccessKeyId + ":" + Signature
Signature = base64(hmac-sha1(AccessKeySecret,
            VERB + "\n"
            + Content-MD5 + "\n" 
            + Content-Type + "\n" 
            + Date + "\n" 
            + CanonicalizedOSSHeaders
            + CanonicalizedResource))

实际编写出来的dart代码:

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);
    //有md5 包含md5
    if (headers.containsKey(HttpHeaders.contentMD5Header)) {
      string.write(headers[HttpHeaders.contentMD5Header]);
    }
    string.writeln();
    //有 type包含type
    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();
      }
    });

    // Append canonicalized oss headers to sign to canonical string
    canonicalizedOssHeadersToSign.forEach((key, value) {
      canonicalOssHeadersString
        ..write(key)
        ..write(':')
        ..writeln(value);
    });
    return canonicalOssHeadersString.toString();
  }
}
  1. 最后在dio拦截器中调用生成签名方法,添加签名到Headers中
_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 上传图片(官网文档)

Future<String> uploadToOss(File image) async {
  var host = "${bucket}.oss-cn-hangzhou.aliyuncs.com";
  var url = "https://${host}";
  ///文件名,后续作为key使用
  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,
  });

  ///参考 https://help.aliyun.com/document_detail/31978.html?spm=a2c4g.11186623.6.1673.50d8c2502BbrCV
  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 权限设置为公共读

img

在公共读权限下,查看图片就变得简单,只需要使用key拼接好url链接就行了。

//拼接规则
var url="https://${bucket}.oss-cn-hangzhou.aliyuncs.com/${objectkey}"
//例子:https://guuguohome.oss-cn-hangzhou.aliyuncs.com/temp_103830-05dbfb795c3c84e2.jpg

第二种参考文档获取链接

看文档看文档看文档

四.结尾

"不就是上传一张图片吗?能有多难?"

看着终于成功上传的图片,我小声呢喃。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容