You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter应用中使用CloudFlare R2实现文件上传?

在Flutter中向CloudFlare R2上传文件的实现方案

CloudFlare R2兼容S3 API,下面提供两种可行的上传实现方式,直接解决请求头签名的问题:

方法一:利用S3兼容签名库(推荐)

通过Dart的AWS签名库自动处理请求头签名,配合http包完成上传,无需手动拼接签名逻辑。

步骤1:添加依赖

在pubspec.yaml中引入所需包:

dependencies:
  http: ^1.1.0
  aws_signature_v4: ^0.4.0
  crypto: ^3.0.3

步骤2:完整上传代码

import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:aws_signature_v4/aws_signature_v4.dart';

Future<void> uploadToR2({
  required String accessKey,
  required String secretKey,
  required String bucketName,
  required String r2AccountId, // 你的R2账户ID,可在CloudFlare控制台获取
  required File targetFile,
  required String objectKey, // 上传后在R2中的文件路径/名称
}) async {
  // 构建R2请求端点
  final url = Uri.parse('https://$r2AccountId.r2.cloudflarestorage.com/$bucketName/$objectKey');

  // 配置签名参数
  final scope = AwsScope(region: 'auto', service: 's3');
  final signer = AwsSignatureV4Signer(
    credentials: AwsCredentials(accessKey: accessKey, secretKey: secretKey),
  );

  // 构建上传请求
  final request = http.MultipartRequest('PUT', url)
    ..files.add(await http.MultipartFile.fromPath('file', targetFile.path));

  // 生成带签名的请求
  final signedRequest = await signer.sign(request, scope: scope);

  // 发送请求并处理响应
  final response = await http.Response.fromStream(await signedRequest.send());
  if (response.statusCode == 200 || response.statusCode == 201) {
    print('文件上传成功');
  } else {
    print('上传失败:${response.statusCode} - ${response.body}');
  }
}

方法二:手动生成请求签名

如果不想依赖第三方库,可以手动实现AWS V4签名逻辑,核心是生成Authorization请求头:

完整手动签名上传代码

import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http;

// HMAC-SHA256加密工具方法
String hmacSha256(String key, String data) {
  final hmac = Hmac(sha256, utf8.encode(key));
  return base64.encode(hmac.convert(utf8.encode(data)).bytes);
}

Future<void> uploadManuallyToR2({
  required String accessKey,
  required String secretKey,
  required String bucketName,
  required String r2AccountId,
  required File targetFile,
  required String objectKey,
}) async {
  final dateTime = DateTime.now().toUtc();
  final dateFull = dateTime.toIso8601String().replaceAll('-', '').replaceAll(':', '').split('.').first + 'Z';
  final dateShort = dateFull.substring(0, 8);

  final url = Uri.parse('https://$r2AccountId.r2.cloudflarestorage.com/$bucketName/$objectKey');

  // 构建规范请求串
  final canonicalRequest = [
    'PUT',
    '/$bucketName/$objectKey',
    '',
    'host:${url.host}',
    'x-amz-content-sha256:UNSIGNED-PAYLOAD',
    'x-amz-date:$dateFull',
    '',
    'host;x-amz-content-sha256;x-amz-date',
    'UNSIGNED-PAYLOAD',
  ].join('\n');

  // 生成签名密钥链
  final kDate = hmacSha256('AWS4$secretKey', dateShort);
  final kRegion = hmacSha256(kDate, 'auto');
  final kService = hmacSha256(kRegion, 's3');
  final kSigning = hmacSha256(kService, 'aws4_request');

  // 生成待签名字符串
  final stringToSign = [
    'AWS4-HMAC-SHA256',
    dateFull,
    '$dateShort/auto/s3/aws4_request',
    sha256.convert(utf8.encode(canonicalRequest)).toString(),
  ].join('\n');

  // 计算最终签名
  final signature = hmacSha256(kSigning, stringToSign);

  // 组装Authorization头
  final authHeader = 'AWS4-HMAC-SHA256 Credential=$accessKey/$dateShort/auto/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=$signature';

  // 发送上传请求
  final response = await http.put(
    url,
    headers: {
      'Authorization': authHeader,
      'x-amz-date': dateFull,
      'x-amz-content-sha256': 'UNSIGNED-PAYLOAD',
      'Content-Type': 'application/octet-stream',
    },
    body: await targetFile.readAsBytes(),
  );

  if (response.statusCode == 200 || response.statusCode == 201) {
    print('文件上传成功');
  } else {
    print('上传失败:${response.statusCode} - ${response.body}');
  }
}

关键注意事项

  • R2账户ID可在CloudFlare控制台的R2存储页面获取
  • 确保你的AccessKey和SecretKey拥有目标存储桶的PUT对象权限
  • 大文件建议使用分块上传(Multipart Upload),可参考S3分块上传逻辑适配R2
  • 方法一的签名库已处理大部分边界情况,优先推荐使用

内容的提问来源于stack exchange,提问作者jitendra purohit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:22:56