flutter---->阿里雲oss的外掛

huhx發表於2023-03-26

目前為止,阿里雲官方並沒有dart版本的oss sdk,所以才開發了這個外掛flutter_oss_aliyun提供對oss sdk的支援。

flutter_oss_aliyun

一個訪問阿里雲oss並且支援STS臨時訪問憑證訪問OSS的flutter庫,基本上涵蓋阿里雲oss sdk的所有功能。⭐

flutter pub: https://pub.dev/packages/flutter_oss_aliyun

github : https://github.com/huhx/flutter_oss_aliyun

oss sts document: https://help.aliyun.com/document_detail/100624.html

?  初始化Client

新增依賴

dependencies:
  flutter_oss_aliyun: ^6.2.2

初始化oss client, 這裡我們提供兩種方式

1. 提供sts server地址,需要後端新增這個api

Client.init(
    stsUrl: "server url get sts token",
    ossEndpoint: "oss-cn-beijing.aliyuncs.com",
    bucketName: "bucket name",
);

後端api至少需要返回以下資料:

{
  "AccessKeyId": "AccessKeyId",
  "AccessKeySecret": "AccessKeySecret",
  "SecurityToken": "SecurityToken",
  "Expiration": "2022-03-22T11:33:06Z"
}

2. 自定義authGetter得到Auth

Client.init(
    ossEndpoint: "oss-cn-beijing.aliyuncs.com",
    bucketName: "bucketName",
    authGetter: _authGetter
);

Auth _authGetter() {
  return Auth(
      accessKey: "accessKey",
      accessSecret: 'accessSecret',
      expire: '2023-02-23T14:02:46Z',
      secureToken: 'token',
  );
}

你可以傳入自定義的Dio

在init函式中,你可以傳入dio,做到dio的定製化。比如日誌或者其他的interceptors.

Client.init(
    stsUrl: "server url get sts token",
    ossEndpoint: "oss-cn-beijing.aliyuncs.com",
    bucketName: "bucket name",
    dio: Dio(BaseOptions(connectTimeout: 9000)),
);

? 使用

檔案上傳

關於callback的使用: https://help.aliyun.com/document_detail/31989.htm?spm=a2c4g.11186623.0.0.73a830ffn45LMY#reference-zkm-311-hgb

final bytes = "file bytes".codeUnits;

await Client().putObject(
  bytes,
  "test.txt",
  option: PutRequestOption(
    onSendProgress: (count, total) {
      print("send: count = $count, and total = $total");
    },
    onReceiveProgress: (count, total) {
      print("receive: count = $count, and total = $total");
    },
    override: false,
    aclModel: AclMode.publicRead,
    storageType: StorageType.ia,
    headers: {"cache-control": "no-cache"},
    callback: Callback(
      callbackUrl: "callback url",
      callbackBody: "{\"mimeType\":\${mimeType}, \"filepath\":\${object},\"size\":\${size},\"bucket\":\${bucket},\"phone\":\${x:phone}}",
      callbackVar: {"x:phone": "android"},
      calbackBodyType: CalbackBodyType.json,
    ),       
  ),
);

PutRequestOption 欄位說明,欄位皆為非必需

Filed Default value Description
override true true: 允許覆蓋同名Object
false: 禁止覆蓋同名Object
aclModel inherited 1. publicWrite: 任何人(包括匿名訪問者)都可以對該Object進行讀寫操作
2. publicRead: 只有該Object的擁有者可以對該Object進行寫操作,任何人(包括匿名訪問者)都可以對該Object進行讀操作
3. private: 只有Object的擁有者可以對該Object進行讀寫操作,其他人無法訪問該Object
4. inherited: 該Object遵循Bucket的讀寫許可權,即Bucket是什麼許可權,Object就是什麼許可權
參考文件: https://help.aliyun.com/document_detail/100676.htm?spm=a2c4g.11186623.0.0.56637952SnxOWV#concept-blw-yqm-2gb
storageType Standard 參考文件: https://help.aliyun.com/document_detail/51374.htm?spm=a2c4g.11186623.0.0.56632b55htpEQX#concept-fcn-3xt-tdb

追加檔案上傳

final Response<dynamic> resp = await Client().appendObject(
  Uint8List.fromList(utf8.encode("Hello World")),
  "test_append.txt",
);

final Response<dynamic> resp2 = await Client().appendObject(
  position: int.parse(resp.headers["x-oss-next-append-position"]?[0]),
  Uint8List.fromList(utf8.encode(", Fluter.")),
  "test_append.txt",
);

跨bucket複製檔案

final Response<dynamic> resp = await Client().copyObject(
  const CopyRequestOption(
    sourceFileKey: 'test.csv',
    targetFileKey: "test_copy.csv",
    targetBucketName: "bucket_2"
  ),
);

取消檔案上傳

final CancelToken cancelToken = CancelToken();
final bytes = ("long long bytes" * 1000).codeUnits;

Client().putObject(
  Uint8List.fromList(utf8.encode(string)),
  "cancel_token_test.txt",
  cancelToken: cancelToken,
  option: PutRequestOption(
    onSendProgress: (count, total) {
      if (kDebugMode) {
        print("send: count = $count, and total = $total");
      }
      if (count > 56) {
        cancelToken.cancel("cancel the uploading.");
      }
    },
  ),
).then((response) {
  // success
  print("upload success = ${response.statusCode}");
}).catchError((err) {
  if (CancelToken.isCancel(err)) {
    print("error message = ${err.message}");
  } else {
    // handle other errors
  }
});

批次檔案上傳

await Client().putObjects([
  AssetEntity(
    filename: "filename1.txt",
    bytes: "files1".codeUnits,
    option: PutRequestOption(
      onSendProgress: (count, total) {
        print("send: count = $count, and total = $total");
      },
      onReceiveProgress: (count, total) {
        print("receive: count = $count, and total = $total");
      },
      aclModel: AclMode.private,
    ),
  ),
  AssetEntity(filename: "filename2.txt", bytes: "files2".codeUnits),
]);

本地檔案上傳

final Response<dynamic> resp = await Client().putObjectFile(
  "/Users/aaa.pdf",
  fileKey: "aaa.png",
  option: PutRequestOption(
    onSendProgress: (count, total) {
      print("send: count = $count, and total = $total");
    },
    onReceiveProgress: (count, total) {
      print("receive: count = $count, and total = $total");
    },
    aclModel: AclMode.private,
  ),
);

批次本地檔案上傳

final List<Response<dynamic>> resp = await Client().putObjectFiles(
  [
    AssetFileEntity(
      filepath: "//Users/private.txt",
      option: PutRequestOption(
        onSendProgress: (count, total) {
          print("send: count = $count, and total = $total");
        },
        onReceiveProgress: (count, total) {
          print("receive: count = $count, and total = $total");
        },
        override: false,
        aclModel: AclMode.private,
      ),
    ),
    AssetFileEntity(
      filepath: "//Users/splash.png",
      filename: "aaa.png",
      option: PutRequestOption(
        onSendProgress: (count, total) {
          print("send: count = $count, and total = $total");
        },
        onReceiveProgress: (count, total) {
          print("receive: count = $count, and total = $total");
        },
        override: true,
      ),
    ),
  ],
);

檔案下載

await Client().getObject(
  "test.txt",
  onReceiveProgress: (count, total) {
    debugPrint("received = $count, total = $total");
  },
);

檔案下載並儲存

await Client().downloadObject(
  "test.txt",
  "./example/test.txt",
  onReceiveProgress: (count, total) {
    debugPrint("received = $count, total = $total");
  },
);

檔案刪除

await Client().deleteObject("test.txt");

批次檔案刪除

await Client().deleteObjects(["filename1.txt", "filename2.txt"]);

獲取已簽名的檔案url

需要注意的是: 這個操作並不安全,因為url包含security-token資訊,即使過期時間比較短. 這個url可以直接在瀏覽器訪問

final String url = await Client().getSignedUrl("filename1.txt");

獲取多個已簽名的檔案url

需要注意的是: 這個操作並不安全,因為url包含security-token資訊,即使過期時間比較短

final Map<String, String> result = await Client().getSignedUrls(["test.txt", "filename1.txt"]);

列舉所有的儲存空間

列舉請求者擁有的所有儲存空間(Bucket)。您還可以透過設定prefix、marker或者max-keys引數列舉滿足指定條件的儲存空間。參考: https://help.aliyun.com/document_detail/31957.html

final Response<dynamic> resp = await Client().listBuckets({"max-keys": 2});

列舉儲存空間中所有檔案

介面用於列舉儲存空間(Bucket)中所有檔案(Object)的資訊。請求引數和返回結果,請參考: https://help.aliyun.com/document_detail/187544.html

final Response<dynamic> resp = await Client().listFiles({});

獲取bucket資訊

檢視儲存空間(Bucket)的相關資訊。返回結果請參考: https://help.aliyun.com/document_detail/31968.html

final Response<dynamic> resp = await Client().getBucketInfo();

獲取bucket的儲容量以及檔案數量

獲取指定儲存空間(Bucket)的儲存容量以及檔案(Object)數量。返回結果請參考: https://help.aliyun.com/document_detail/426056.html

final Response<dynamic> resp = await Client().getBucketStat();

獲取檔案元資訊

final Response<dynamic> resp = await Client().getObjectMeta("huhx.csv");

regions的查詢

  • 查詢所有
final Response<dynamic> resp = await Client().getAllRegions();
  • 查詢特定
final Response<dynamic> resp = await Client().getRegion("oss-ap-northeast-1");

bucket acl的操作

  • 查詢
final Response<dynamic> resp = await Client().getBucketAcl(
  bucketName: "bucket-name",
);
  • 更新
final Response<dynamic> resp = await Client().putBucketAcl(
  AciMode.publicRead, 
  bucketName: "bucket-name",
);

bucket policy的操作

  • 查詢
final Response<dynamic> resp = await Client().getBucketPolicy(
  bucketName: "bucket-name",
);
  • 更新
final Response<dynamic> resp = await Client().putBucketPolicy(
  {}, 
  bucketName: "bucket-name",
);
  • 刪除
final Response<dynamic> resp = await Client().deleteBucketPolicy(
  bucketName: "bucket-name",
);

相關文章