前言
在 Flutter Web 在《一起漫部》的效能最佳化探索與實踐 一文中,
在做載入最佳化時需要實現資原始檔cdn化,意味著要將資原始檔上傳到騰訊的COS或者阿里的OSS這樣的第三方物件儲存伺服器。 目前公司使用的是騰訊的物件儲存(COS),原本想用官方提供的SDK去實現資源上傳功能,但是官方並沒有提供Dart版本的SDK, 去pub.dev
搜了下關於cos的相關外掛,也沒有找到功能相對完善的外掛,於是便打算手寫一個Dart版本物件儲存(COS)外掛。
簡介
在官方提供的API功能過於豐富和時間有限的情況下,只實現了部分功能:
- 支援
Bucket
介面的基本操作,增加、刪除、查詢儲存桶等 - 支援
Bucket
介面的訪問控制(acl) - 支援
Bucket
介面的跨域資源共享(cors) - 支援
Bucket
介面的防盜鏈(referer) - 支援
Object
介面的基本操作,上傳、刪除、查詢儲存物件等 - 支援
Object
介面的訪問控制(acl)
結構
工程主要包括示例(example)、核心程式碼(lib)和單元測試(test)三部分
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── example // 示例
├── lib // 核心程式碼
│ ├── src
│ │ ├── api
│ │ ├── client
│ │ ├── model
│ │ └── src.dart
│ └── tencent_cos_plus.dart
├── pubspec.lock
├── pubspec.yaml
├── tencent_cos_plus.iml
└── test // 單元測試
示例
示例目前僅包括tencent_cos_plus_example.dart
檔案,主要是介紹如何使用外掛,包括初始化配置、儲存桶Api呼叫和儲存物件 Api呼叫。
├── example
│ └── tencent_cos_plus_example.dart
核心程式碼
核心程式碼(lib)部分由client
、api
和model
三層構成:
client
層封裝了http請求和介面簽名功能api
層實現了儲存桶(bucket)和儲存物件(object)部分api的呼叫model
層負責xml資料和實體物件的解析
├── api
│ ├── api.dart
│ ├── cos_abstract_api.dart
│ ├── cos_api_factory.dart
│ ├── cos_api_mixin.dart
│ ├── cos_bucket_api.dart
│ └── cos_object_api.dart
├── client
│ ├── client.dart
│ └── cos_client.dart
├── model
│ ├── common
│ │ ├── cos_access_control_policy.dart
│ │ ├── cos_common.dart
│ │ ├── cos_config.dart
│ │ ├── cos_cors_configuration.dart
│ │ ├── cos_exception.dart
│ │ └── cos_referer_configuration.dart
│ ├── model.dart
│ ├── request
│ │ ├── cos_bucket_acl_header.dart
│ │ ├── cos_create_bucket_configuration.dart
│ │ ├── cos_delete.dart
│ │ ├── cos_get_object.dart
│ │ └── cos_restore_request.dart
│ └── response
│ ├── cos_copy_object_result.dart
│ ├── cos_delete_result.dart
│ ├── cos_list_all_my_buckets_result.dart
│ ├── cos_list_bucket_result.dart
│ └── cos_list_versions_result.dart
單元測試
單元測試包括cos_bucket_api_test.dart
和cos_object_api_test.dart
兩個檔案,主要是覆蓋了儲存桶(bucket)
和儲存物件(object)部分api的單元測試
└── test
├── cos_bucket_api_test.dart
└── cos_object_api_test.dart
使用說明
關於如何使用,請參考 README
碰到的問題
在開發過程中,實現需要提交xml資料的介面時,出現簽名不匹配的問題。
<?xml version='1.0' encoding='utf-8' ?>
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The Signature you specified is invalid.</Message>
<StringToSign>sha1
1666158568;1666218568
488ab174d5f7a6ec0966aeeb82600e185114d7d1
</StringToSign>
<FormatString>put
/
cors=
content-length=454&content-md5=DfuiC7IOBwIeiVanWPG%2FKg%3D%3D&content-type=application%2Fxml%3B%20charset%3Dutf-8&date=Wed%2C%2019%20Oct%202022%2005%3A49%3A28%20GMT&host=test-app-1251021022.cos.ap-guangzhou.myqcloud.com
</FormatString>
<Resource>/</Resource>
<RequestId>NjM0ZjhmZThfNDgzNjQwMGJfMTMwZWFfNDhmODEyZg==</RequestId>
<TraceId>OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTBjYzE2MjAxN2M1MzJiOTdkZjMxMDVlYTZjN2FiMmI0MjFmNzE4ZjVmM2M0ZTcxNjYwMmQ3N2QzYjA3NzYyNmM=</TraceId>
</Error>
出現這個問題後,先是確認了簽名文件提供的簽名規則是否一致,然後使用 COS 簽名工具
去驗證簽名結果是否一致,發現在都沒有問題。最後透過api介面返回的錯誤資訊,發現參與簽名的content-type
和提交給api的content-type
不一致,導致簽名不匹配。
透過斷點除錯,排查到是使用的 http 外掛造成的,在設定body
時如果content-type
沒有charset
時會賦值預設的charset
,問題找到了。
其它
- 目前不足的是上傳檔案和下載檔案時,沒有進度的回撥
總結
整個外掛實現起來不難,主要需要花時間閱讀騰訊物件儲存(COS)文件,根據Api文件進行封裝和測試,這裡開源出來給需要的人提供幫助。
- pub: tencent_cos_plus
- git: flutter_tencent_cos_plus