yx_oss_flutter/example/main.dart

535 lines
15 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:typed_data';
import 'package:yx_oss/yx_oss.dart';
/// YX OSS 使用示例
///
/// 展示如何使用不同的认证和配置方式
void main() async {
print('YX OSS 使用示例');
// 示例1: 静态配置 + 静态认证
await example1StaticAuth();
// 示例2: STS临时凭证认证
await example2STSAuth();
// 示例3: 预签名URL认证
await example3PreSignedAuth();
// 示例4: 动态配置
await example4DynamicConfig();
// 示例5: 分片上传
await example5MultipartUpload();
}
/// 示例1: 静态配置 + 静态认证
/// 适用场景: 开发测试环境,简单的应用场景
Future<void> example1StaticAuth() async {
print('\n=== 示例1: 静态配置 + 静态认证 ===');
// 创建静态认证提供者
const authProvider = StaticAuthProvider(
accessKeyId: 'your_access_key_id',
accessKeySecret: 'your_access_key_secret',
);
// 创建静态配置提供者
const configProvider = StaticConfigProvider(
endpoint: 'oss-cn-hangzhou.aliyuncs.com',
bucketName: 'your-bucket-name',
directory: 'uploads', // 可选,默认为'uploads'
domain: 'https://your-custom-domain.com', // 可选,自定义域名
);
// 创建OSS客户端配置
const config = YxOSSConfig(
authProvider: authProvider,
configProvider: configProvider,
// 可选的超时配置
timeoutConfig: TimeoutConfig(
connectTimeout: 60000,
sendTimeout: 300000,
receiveTimeout: 300000,
),
// 可选的重试配置
retryConfig: RetryConfig(
maxRetries: 3,
initialInterval: 1000,
enableExponentialBackoff: true,
),
// 可选的日志配置
logConfig: LogConfig(
enabled: true,
level: LogLevel.info,
logRequest: false,
logResponse: false,
logError: true,
),
);
// 创建OSS客户端
final client = YxOSSClient(config);
try {
// 初始化客户端
await client.initialize();
// 准备上传的文件数据
final fileData = Uint8List.fromList('Hello, YX OSS!'.codeUnits);
// 创建上传选项
final options = UploadOptions(
overwrite: true,
acl: ACLMode.publicRead,
storageClass: StorageClass.standard,
contentType: 'text/plain',
metadata: {'author': 'YX OSS Example'},
callbacks: UploadCallbacks(
onStart: () => print('开始上传...'),
onProgress: (sent, total) {
final progress = (sent / total * 100).toStringAsFixed(1);
print('上传进度: $progress% ($sent/$total)');
},
onSuccess: (result) => print('上传成功: ${result.url}'),
onError: (error) => print('上传失败: $error'),
onComplete: () => print('上传完成'),
),
);
// 执行上传
final result = await client.uploadBytes(
fileData,
'examples/test-file.txt',
options: options,
);
print('上传结果:');
print(' URL: ${result.url}');
print(' 对象键: ${result.objectKey}');
print(' 文件大小: ${result.fileSize} 字节');
print(' ETag: ${result.etag}');
print(' 上传耗时: ${result.uploadDuration} 毫秒');
} catch (e) {
print('操作失败: $e');
} finally {
// 释放资源
client.dispose();
}
}
/// 示例2: STS临时凭证认证
/// 适用场景: 生产环境,需要动态权限控制
Future<void> example2STSAuth() async {
print('\n=== 示例2: STS临时凭证认证 ===');
// 模拟从服务器获取STS凭证的函数
Future<STSCredentials> getSTSCredentials() async {
// 实际应用中这里应该调用您的后端API获取STS凭证
// 这里只是示例数据
return STSCredentials(
accessKeyId: 'STS.your_sts_access_key_id',
accessKeySecret: 'your_sts_access_key_secret',
securityToken: 'your_security_token',
expiration: DateTime.now().add(const Duration(hours: 1)),
);
}
// 创建STS认证提供者
final stsCredentials = await getSTSCredentials();
final authProvider = STSAuthProvider(
accessKeyId: stsCredentials.accessKeyId,
accessKeySecret: stsCredentials.accessKeySecret,
securityToken: stsCredentials.securityToken,
expiration: stsCredentials.expiration,
credentialsGetter: getSTSCredentials, // 凭证过期时自动刷新
);
const configProvider = StaticConfigProvider(
endpoint: 'oss-cn-hangzhou.aliyuncs.com',
bucketName: 'your-bucket-name',
directory: 'sts-uploads',
);
final config = YxOSSConfig(
authProvider: authProvider,
configProvider: configProvider,
);
final client = YxOSSClient(config);
try {
await client.initialize();
final fileData = Uint8List.fromList('STS upload test'.codeUnits);
final result = await client.uploadBytes(
fileData,
'sts-test-file.txt',
options: UploadOptions(
callbacks: UploadCallbacks(
onProgress: (sent, total) {
print('STS上传进度: ${(sent / total * 100).toStringAsFixed(1)}%');
},
),
),
);
print('STS上传成功: ${result.url}');
} catch (e) {
print('STS上传失败: $e');
} finally {
client.dispose();
}
}
/// 示例3: 预签名URL认证
/// 适用场景: 客户端直接上传,服务端控制权限
Future<void> example3PreSignedAuth() async {
print('\n=== 示例3: 预签名URL认证 ===');
// 模拟从服务器获取预签名URL的函数
Future<String> getPreSignedUrl(String fileName) async {
// 实际应用中这里应该调用您的后端API获取预签名URL
// 后端会根据文件名和权限策略生成预签名URL
return 'https://your-bucket.oss-cn-hangzhou.aliyuncs.com/uploads/$fileName?Expires=1234567890&OSSAccessKeyId=your_key&Signature=signature';
}
// 创建预签名URL认证提供者
final authProvider = PreSignedAuthProvider(
urlGetter: getPreSignedUrl,
);
// 注意预签名URL模式下配置提供者仍然需要但某些配置可能不会被使用
const configProvider = StaticConfigProvider(
endpoint: 'oss-cn-hangzhou.aliyuncs.com',
bucketName: 'your-bucket-name',
directory: '', // 预签名URL通常已包含完整路径
);
final config = YxOSSConfig(
authProvider: authProvider,
configProvider: configProvider,
);
final client = YxOSSClient(config);
try {
await client.initialize();
final fileData = Uint8List.fromList('PreSigned URL upload test'.codeUnits);
final result = await client.uploadBytes(
fileData,
'presigned-test-file.txt',
options: UploadOptions(
callbacks: UploadCallbacks(
onProgress: (sent, total) {
print('预签名上传进度: ${(sent / total * 100).toStringAsFixed(1)}%');
},
),
),
);
print('预签名上传成功: ${result.url}');
} catch (e) {
print('预签名上传失败: $e');
} finally {
client.dispose();
}
}
/// 示例4: 动态配置
/// 适用场景: 配置信息需要从服务器动态获取
Future<void> example4DynamicConfig() async {
print('\n=== 示例4: 动态配置 ===');
// 模拟从服务器获取OSS配置的函数
Future<OSSConfig> getOSSConfig() async {
// 实际应用中这里应该调用您的后端API获取OSS配置
return const OSSConfig(
endpoint: 'oss-cn-hangzhou.aliyuncs.com',
bucketName: 'dynamic-bucket-name',
directory: 'dynamic-uploads',
domain: 'https://cdn.example.com',
);
}
const authProvider = StaticAuthProvider(
accessKeyId: 'your_access_key_id',
accessKeySecret: 'your_access_key_secret',
);
// 创建动态配置提供者
final configProvider = DynamicConfigProvider(
configGetter: getOSSConfig,
cacheTimeout: const Duration(minutes: 30), // 配置缓存30分钟
);
final config = YxOSSConfig(
authProvider: authProvider,
configProvider: configProvider,
);
final client = YxOSSClient(config);
try {
await client.initialize();
final fileData = Uint8List.fromList('Dynamic config upload test'.codeUnits);
final result = await client.uploadBytes(
fileData,
'dynamic-config-test.txt',
options: UploadOptions(
callbacks: UploadCallbacks(
onProgress: (sent, total) {
print('动态配置上传进度: ${(sent / total * 100).toStringAsFixed(1)}%');
},
),
),
);
print('动态配置上传成功: ${result.url}');
} catch (e) {
print('动态配置上传失败: $e');
} finally {
client.dispose();
}
}
/// 示例5: 分片上传
/// 适用场景: 大文件上传,需要支持断点续传和并发上传
Future<void> example5MultipartUpload() async {
print('\n=== 示例5: 分片上传 ===');
const authProvider = StaticAuthProvider(
accessKeyId: 'your_access_key_id',
accessKeySecret: 'your_access_key_secret',
);
const configProvider = StaticConfigProvider(
endpoint: 'oss-cn-hangzhou.aliyuncs.com',
bucketName: 'your-bucket-name',
directory: 'large-files',
);
const config = YxOSSConfig(
authProvider: authProvider,
configProvider: configProvider,
);
final client = YxOSSClient(config);
try {
await client.initialize();
// 模拟大文件数据200MB
final largeFileData = Uint8List(200 * 1024 * 1024);
for (int i = 0; i < largeFileData.length; i++) {
largeFileData[i] = i % 256;
}
print(
'准备上传 ${YxOSSFileUtils.formatFileSize(largeFileData.length)} 的大文件...');
final options = UploadOptions(
// 启用分片上传
enableMultipart: true,
// 分片大小设置为10MB
partSize: 10 * 1024 * 1024,
// 并发上传3个分片
concurrency: 3,
// 100MB以上的文件使用分片上传
multipartThreshold: 100 * 1024 * 1024,
callbacks: UploadCallbacks(
onStart: () => print('开始分片上传...'),
onProgress: (sent, total) {
final progress = (sent / total * 100).toStringAsFixed(1);
final speed = YxOSSFileUtils.formatFileSize(sent ~/ 10); // 假设10秒速度
print('分片上传进度: $progress% - 速度: $speed');
},
onSuccess: (result) {
if (result is MultipartUploadResult) {
print('分片上传成功:');
print(' URL: ${result.url}');
print(' 分片数量: ${result.partCount}');
print(' 上传ID: ${result.uploadId}');
print(' 总耗时: ${result.uploadDuration} 毫秒');
}
},
onError: (error) => print('分片上传失败: $error'),
onComplete: () => print('分片上传完成'),
),
);
final result = await client.uploadBytes(
largeFileData,
'large-file-${DateTime.now().millisecondsSinceEpoch}.dat',
options: options,
);
print('大文件上传结果: ${result.url}');
} catch (e) {
print('大文件上传失败: $e');
} finally {
client.dispose();
}
}
/// 示例6: 错误处理和重试
Future<void> example6ErrorHandling() async {
print('\n=== 示例6: 错误处理和重试 ===');
const authProvider = StaticAuthProvider(
accessKeyId: 'invalid_key', // 故意使用错误的key来演示错误处理
accessKeySecret: 'invalid_secret',
);
const configProvider = StaticConfigProvider(
endpoint: 'oss-cn-hangzhou.aliyuncs.com',
bucketName: 'your-bucket-name',
);
const config = YxOSSConfig(
authProvider: authProvider,
configProvider: configProvider,
// 配置重试策略
retryConfig: RetryConfig(
maxRetries: 3,
initialInterval: 1000,
backoffMultiplier: 2.0,
enableExponentialBackoff: true,
),
);
final client = YxOSSClient(config);
try {
await client.initialize();
final fileData = Uint8List.fromList('Error handling test'.codeUnits);
await client.uploadBytes(
fileData,
'error-test.txt',
options: UploadOptions(
callbacks: UploadCallbacks(
onError: (error) {
print('捕获到错误:');
print(' 类型: ${error.type}');
print(' 消息: ${error.message}');
print(' 状态码: ${error.statusCode ?? 'N/A'}');
print(' 请求ID: ${error.requestId ?? 'N/A'}');
print(' 是否可重试: ${error.isRetryable}');
},
),
),
);
} catch (e) {
if (e is OSSError) {
print('OSS错误详情:');
print(' 错误类型: ${e.type}');
print(' 错误代码: ${e.code}');
print(' 错误消息: ${e.message}');
print(' HTTP状态码: ${e.statusCode}');
print(' 是否为认证错误: ${e.isAuthenticationError}');
print(' 是否为网络错误: ${e.isNetworkError}');
} else {
print('未知错误: $e');
}
} finally {
client.dispose();
}
}
/// 示例7: 集成到项目中的适配器模式
class ProjectOSSAdapter {
late final YxOSSClient _client;
/// 初始化适配器
Future<void> initialize({
required String endpoint,
required String bucketName,
required String accessKeyId,
required String accessKeySecret,
String? customDomain,
}) async {
final authProvider = StaticAuthProvider(
accessKeyId: accessKeyId,
accessKeySecret: accessKeySecret,
);
final configProvider = StaticConfigProvider(
endpoint: endpoint,
bucketName: bucketName,
directory: 'app-uploads',
domain: customDomain,
);
final config = YxOSSConfig(
authProvider: authProvider,
configProvider: configProvider,
logConfig: const LogConfig(
enabled: true,
level: LogLevel.warning, // 生产环境只记录警告和错误
),
);
_client = YxOSSClient(config);
await _client.initialize();
}
/// 上传图片文件
Future<String> uploadImage(
Uint8List imageData,
String fileName, {
Function(double progress)? onProgress,
}) async {
final result = await _client.uploadBytes(
imageData,
'images/${YxOSSFileUtils.generateUniqueFileName(originalFileName: fileName)}',
options: UploadOptions(
contentType: YxOSSFileUtils.guessMimeType(fileName),
acl: ACLMode.publicRead,
callbacks: UploadCallbacks(
onProgress: (sent, total) {
onProgress?.call(sent / total);
},
),
),
);
return result.url;
}
/// 上传文档文件
Future<String> uploadDocument(
Uint8List documentData,
String fileName, {
Function(double progress)? onProgress,
}) async {
final result = await _client.uploadBytes(
documentData,
'documents/${YxOSSFileUtils.generateUniqueFileName(originalFileName: fileName)}',
options: UploadOptions(
contentType: YxOSSFileUtils.guessMimeType(fileName),
acl: ACLMode.private, // 文档默认私有
callbacks: UploadCallbacks(
onProgress: (sent, total) {
onProgress?.call(sent / total);
},
),
),
);
return result.url;
}
/// 释放资源
void dispose() {
_client.dispose();
}
}