开发者社区> 问答> 正文

ios 断点续传 碎片如何处理

已解决

展开
收起
2018-03-11 09:45:21 994 0
1 条回答
写回答
取消 提交回答
  • 采纳回答

    详细解答可以参考官方帮助文档

    OSS 移动端SDK 上传文件的方式可以分为:简单上传,追加上传,分片上传和断点续传。

    简单上传

    上传Object可以直接上传OSSData,或者通过NSURL上传一个文件:

    1. OSSPutObjectRequest * put = [OSSPutObjectRequest new];
    2. // 必填字段
    3. put.bucketName = @"<bucketName>";
    4. put.objectKey = @"<objectKey>";
    5. put.uploadingFileURL = [NSURL fileURLWithPath:@"<filepath>"];
    6. // put.uploadingData = <NSData *>; // 直接上传NSData
    7. // 可选字段,可不设置
    8. put.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
    9. // 当前上传段长度、当前已经上传总长度、一共需要上传的总长度
    10. NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
    11. };
    12. // 以下可选字段的含义参考: https://docs.aliyun.com/#/pub/oss/api-reference/object&PutObject
    13. // put.contentType = @"";
    14. // put.contentMd5 = @"";
    15. // put.contentEncoding = @"";
    16. // put.contentDisposition = @"";
    17. // put.objectMeta = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"value1", @"x-oss-meta-name1", nil]; // 可以在上传时设置元信息或者其他HTTP头部
    18. OSSTask * putTask = [client putObject:put];
    19. [putTask continueWithBlock:^id(OSSTask *task) {
    20. if (!task.error) {
    21. NSLog(@"upload object success!");
    22. } else {
    23. NSLog(@"upload object failed, error: %@" , task.error);
    24. }
    25. return nil;
    26. }];
    27. // [putTask waitUntilFinished];
    28. // [put cancel];

    上传到文件目录

    OSS服务是没有文件夹这个概念的,所有元素都是以文件来存储,但给用户提供了创建模拟文件夹的方式。创建模拟文件夹本质上来说是创建了一个名字以“/”结尾的文件,对于这个文件照样可以上传下载,只是控制台会对以“/”结尾的文件以文件夹的方式展示。

    如,在上传文件是,如果把ObjectKey写为"folder/subfolder/file",即是模拟了把文件上传到folder/subfolder/下的file文件。注意,路径默认是”根目录”,不需要以’/‘开头。

    上传时设置Content-Type和开启校验MD5

    上传时可以显式指定ContentType,如果没有指定,SDK会根据文件名或者上传的ObjectKey自动判断。另外,上传Object时如果设置了Content-Md5,那么OSS会用之检查消息内容是否与发送时一致。SDK提供了方便的Base64和MD5计算方法。

    1. OSSPutObjectRequest * put = [OSSPutObjectRequest new];
    2. // 必填字段
    3. put.bucketName = @"<bucketName>";
    4. put.objectKey = @"<objectKey>";
    5. put.uploadingFileURL = [NSURL fileURLWithPath:@"<filepath>"];
    6. // put.uploadingData = <NSData *>; // 直接上传NSData
    7. // 设置Content-Type,可选
    8. put.contentType = @"application/octet-stream";
    9. // 设置MD5校验,可选
    10. put.contentMd5 = [OSSUtil base64Md5ForFilePath:@"<filePath>"]; // 如果是文件路径
    11. // put.contentMd5 = [OSSUtil base64Md5ForData:<NSData *>]; // 如果是二进制数据
    12. // 进度设置,可选
    13. put.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
    14. // 当前上传段长度、当前已经上传总长度、一共需要上传的总长度
    15. NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
    16. };
    17. OSSTask * putTask = [client putObject:put];
    18. [putTask continueWithBlock:^id(OSSTask *task) {
    19. if (!task.error) {
    20. NSLog(@"upload object success!");
    21. } else {
    22. NSLog(@"upload object failed, error: %@" , task.error);
    23. }
    24. return nil;
    25. }];
    26. // [putTask waitUntilFinished];
    27. // [put cancel];

    追加上传

    Append Object以追加写的方式上传文件。通过Append Object操作创建的Object类型为Appendable Object,而通过Put Object上传的Object是Normal Object。

    1. OSSAppendObjectRequest * append = [OSSAppendObjectRequest new];
    2. // 必填字段
    3. append.bucketName = @"<bucketName>";
    4. append.objectKey = @"<objectKey>";
    5. append.appendPosition = 0; // 指定从何处进行追加
    6. NSString * docDir = [self getDocumentDirectory];
    7. append.uploadingFileURL = [NSURL fileURLWithPath:@"<filepath>"];
    8. // 可选字段
    9. append.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
    10. NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
    11. };
    12. // 以下可选字段的含义参考:https://docs.aliyun.com/#/pub/oss/api-reference/object&AppendObject
    13. // append.contentType = @"";
    14. // append.contentMd5 = @"";
    15. // append.contentEncoding = @"";
    16. // append.contentDisposition = @"";
    17. OSSTask * appendTask = [client appendObject:append];
    18. [appendTask continueWithBlock:^id(OSSTask *task) {
    19. NSLog(@"objectKey: %@", append.objectKey);
    20. if (!task.error) {
    21. NSLog(@"append object success!");
    22. OSSAppendObjectResult * result = task.result;
    23. NSString * etag = result.eTag;
    24. long nextPosition = result.xOssNextAppendPosition;
    25. } else {
    26. NSLog(@"append object failed, error: %@" , task.error);
    27. }
    28. return nil;
    29. }];

    上传后回调通知

    客户端在上传Object时可以指定OSS服务端在处理完上传请求后,通知您的业务服务器,在该服务器确认接收了该回调后将回调的结果返回给客户端。因为加入了回调请求和响应的过程,相比简单上传,使用回调通知机制一般会导致客户端花费更多的等待时间。

    具体说明参考:Callback

    代码示例:

    1. OSSPutObjectRequest * request = [OSSPutObjectRequest new];
    2. request.bucketName = @"<bucketName>";
    3. request.objectKey = @"<objectKey>";
    4. request.uploadingFileURL = [NSURL fileURLWithPath:@<filepath>"];
    5. // 设置回调参数
    6. request.callbackParam = @{
    7. @"callbackUrl": @"<your server callback address>",
    8. @"callbackBody": @"<your callback body>"
    9. };
    10. // 设置自定义变量
    11. request.callbackVar = @{
    12. @"<var1>": @"<value1>",
    13. @"<var2>": @"<value2>"
    14. };
    15. request.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
    16. NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
    17. };
    18. OSSTask * task = [client putObject:request];
    19. [task continueWithBlock:^id(OSSTask *task) {
    20. if (task.error) {
    21. OSSLogError(@"%@", task.error);
    22. } else {
    23. OSSPutObjectResult * result = task.result;
    24. NSLog(@"Result - requestId: %@, headerFields: %@, servercallback: %@",
    25. result.requestId,
    26. result.httpResponseHeaderFields,
    27. result.serverReturnJsonString);
    28. }
    29. return nil;
    30. }];

    分片上传

    因为篇幅的原因,分片上传参考:分片上传

    断点续传

    特别注意

    • 断点续传暂时只支持上传本地文件。

    • 对于移动端来说,如果不是比较大的文件,不建议使用这种方式上传,因为断点续传是通过分片上传实现的,上传单个文件需要进行多次网络请求,效率不高。**

    在无线网络下,上传比较大的文件持续时间长,可能会遇到因为网络条件差、用户切换网络等原因导致上传中途失败,整个文件需要重新上传。为此,SDK提供了断点上传功能。

    在上传前,可以指定断点记录的保存文件夹。若不进行此项设置,断点上传只在本次上传生效,某个分片因为网络原因等上传失败时会进行重试,避免整个大文件重新上传,节省重试时间和耗用流量。如果设置了断点记录的保存文件夹,如果任务失败,在下次重新启动任务,上传同一文件到同一Bucket、Object时,如果用户设置取消时不删除断点记录。再次上传将从断点记录处继续上传。详见随后的范例。

    断点续传失败时,如果同一任务一直得不到续传,可能会在OSS上积累无用碎片。对这种情况,可以为Bucket设置lifeCycle规则,定时清理碎片。参考:生命周期管理

    出于碎片管理的原因,如果在断点续传时取消当前任务。默认会同步清理已经上传到服务器的分片。如果取消时需要保留断点上传记录,需要指定断点记录的保存文件夹并修改deleteUploadIdOnCancelling参数。需要注意,如果本地保留记录时间过长,且Bucket设置lifeCycle规则定时清理了服务端分片。会出现服务端和移动端记录不一致的问题。

    说明:

    • 断点续传的实现依赖InitMultipartUpload/UploadPart/ListParts/CompleteMultipartUpload/AbortMultipartUpload,如果采用STS鉴权模式,请注意加上这些API所需的权限。

    • 断点续传也支持上传后回调通知,用法和上述普通上传回调通知一致。

    • 断点续传已经默认开启每个分片上传时的Md5校验,请勿重复在request中设置Content-Md5头部。

    在本地持久保存断点记录的调用方式(默认是不设置)

    1. OSSResumableUploadRequest * resumableUpload = [OSSResumableUploadRequest new];
    2. resumableUpload.bucketName = OSS_BUCKET_PRIVATE;
    3. //...
    4. NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
    5. resumableUpload.recordDirectoryPath = cachesDir;

    断点续传功能实现

    1. // 获得UploadId进行上传,如果任务失败并且可以续传,利用同一个UploadId可以上传同一文件到同一个OSS上的存储对象
    2. OSSResumableUploadRequest * resumableUpload = [OSSResumableUploadRequest new];
    3. resumableUpload.bucketName = <bucketName>;
    4. resumableUpload.objectKey = <objectKey>;
    5. resumableUpload.partSize = 1024 * 1024;
    6. resumableUpload.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
    7. NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
    8. };
    9. NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
    10. //设置断点记录文件
    11. resumableUpload.recordDirectoryPath = cachesDir;
    12. //设置NO,取消时,不删除断点记录文件,如果不进行设置,默认YES,是会删除断点记录文件,下次再进行上传时会重新上传。
    13. resumableUpload.deleteUploadIdOnCancelling = NO;
    14. resumableUpload.uploadingFileURL = [NSURL fileURLWithPath:<your file path>];
    15. OSSTask * resumeTask = [client resumableUpload:resumableUpload];
    16. [resumeTask continueWithBlock:^id(OSSTask *task) {
    17. if (task.error) {
    18. NSLog(@"error: %@", task.error);
    19. if ([task.error.domain isEqualToString:OSSClientErrorDomain] && task.error.code == OSSClientErrorCodeCannotResumeUpload) {
    20. // 该任务无法续传,需要获取新的uploadId重新上传
    21. }
    22. } else {
    23. NSLog(@"Upload file success");
    24. }
    25. return nil;
    26. }];
    27. // [resumeTask waitUntilFinished];
    28. // [resumableUpload cancel];

    数据完整性校验

    因为移动端网络环境的复杂性,OSS SDK提供了基于MD5和CRC64的端到端的数据完整性验证功能。

    MD5校验

    需要在上传文件时提供文件的Content-MD5值,OSS服务器会帮助用户进行MD5校验,只有在OSS服务器计算接收到的文件得到的MD5值和上传提供的MD5一致时才可以上传成功,从而保证上传数据的完整性。

    1. OSSPutObjectRequest * request = [OSSPutObjectRequest new];
    2. request.bucketName = BUCKET_NAME;
    3. ...
    4. request.contentMd5 = [OSSUtil fileMD5String:filepath];

    CRC校验

    与MD5相比,CRC64可以同时上传并计算CRC值。

    1. // 构造上传请求
    2. OSSPutObjectRequest * request = [OSSPutObjectRequest new];
    3. request.bucketName = OSS_BUCKET_PRIVATE;
    4. ///....
    5. request.crcFlag = OSSRequestCRCOpen;
    6. // 开启crc效验后。如果在传输中数据不一致,会提示OSSClientErrorCodeInvalidCRC 错误。
    7. OSSTask * task = [_client putObject:request];
    8. [[task continueWithBlock:^id(OSSTask *task) {
    9. //如果crc效验失败,会有error
    10. XCTAssertNil(task.error);
    11. return nil;
    12. }] waitUntilFinished];
    2018-03-17 16:26:38
    赞同 展开评论 打赏
问答分类:
问答标签:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
手淘iOS性能优化探索 立即下载
From Java/Android to Swift iOS 立即下载
深入剖析iOS性能优化 立即下载