OSS 移動端SDK 上傳檔案的方式可以分為:簡單上傳,追加上傳,分區上傳和斷點續傳。
簡單上傳
上傳Object可以直接上傳OSSData,或者通過NSURL上傳一個檔案:
OSSPutObjectRequest * put = [OSSPutObjectRequest new];
// 必要欄位
put.bucketName = @"<bucketName>";
put.objectKey = @"<objectKey>";
put.uploadingFileURL = [NSURL fileURLWithPath:@"<filepath>"];
// put.uploadingData = <NSData *>; // 直接上傳NSData
// 可選欄位,可不設定
put.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
// 當前上傳段長度、當前已經上傳總長度、一共需要上傳的總長度
NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};
// 以下可選欄位的含義參考: https://docs.aliyun.com/#/pub/oss/api-reference/object&PutObject
// put.contentType = @"";
// put.contentMd5 = @"";
// put.contentEncoding = @"";
// put.contentDisposition = @"";
// put.objectMeta = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"value1", @"x-oss-meta-name1", nil]; // 可以在上傳時設定元資訊或者其他HTTP頭部
OSSTask * putTask = [client putObject:put];
[putTask continueWithBlock:^id(OSSTask *task) {
if (!task.error) {
NSLog(@"upload object success!");
} else {
NSLog(@"upload object failed, error: %@" , task.error);
}
return nil;
}];
// [putTask waitUntilFinished];
// [put cancel];
上傳到檔案目錄
OSS服務是沒有檔案夾這個概念的,所有元素都是以檔案來儲存,但給使用者提供了建立模擬檔案夾的方式。建立模擬檔案夾本質上來說是建立了一個名字以“/”結尾的檔案,對於這個檔案照樣可以上傳下載,只是控制台會對以“/”結尾的檔案以檔案夾的方式展示。
如,在上傳檔案是,如果把ObjectKey寫為"folder/subfolder/file"
,即是模擬了把檔案上傳到folder/subfolder/
下的file
檔案。注意,路徑預設是”根目錄”,不需要以’/‘開頭。
上傳時設定Content-Type和開啟校驗MD5
上傳時可以顯式指定ContentType,如果沒有指定,SDK會根據檔案名或者上傳的ObjectKey自動判斷。另外,上傳Object時如果設定了Content-Md5,那麼OSS會用之檢查消息內容是否與發送時一致。SDK提供了方便的Base64和MD5計算方法。
OSSPutObjectRequest * put = [OSSPutObjectRequest new];
// 必要欄位
put.bucketName = @"<bucketName>";
put.objectKey = @"<objectKey>";
put.uploadingFileURL = [NSURL fileURLWithPath:@"<filepath>"];
// put.uploadingData = <NSData *>; // 直接上傳NSData
// 設定Content-Type,可選
put.contentType = @"application/octet-stream";
// 設定MD5校驗,可選
put.contentMd5 = [OSSUtil base64Md5ForFilePath:@"<filePath>"]; // 如果是檔案路徑
// put.contentMd5 = [OSSUtil base64Md5ForData:<NSData *>]; // 如果是位元據
// 進度設定,可選
put.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
// 當前上傳段長度、當前已經上傳總長度、一共需要上傳的總長度
NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};
OSSTask * putTask = [client putObject:put];
[putTask continueWithBlock:^id(OSSTask *task) {
if (!task.error) {
NSLog(@"upload object success!");
} else {
NSLog(@"upload object failed, error: %@" , task.error);
}
return nil;
}];
// [putTask waitUntilFinished];
// [put cancel];
追加上傳
Append Object以追加寫的方式上傳檔案。通過Append Object操作建立的Object類型為Appendable Object,而通過Put Object上傳的Object是Normal Object。
OSSAppendObjectRequest * append = [OSSAppendObjectRequest new];
// 必要欄位
append.bucketName = @"<bucketName>";
append.objectKey = @"<objectKey>";
append.appendPosition = 0; // 指定從何處進行追加
NSString * docDir = [self getDocumentDirectory];
append.uploadingFileURL = [NSURL fileURLWithPath:@"<filepath>"];
// 可選欄位
append.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};
// 以下可選欄位的含義參考:https://docs.aliyun.com/#/pub/oss/api-reference/object&AppendObject
// append.contentType = @"";
// append.contentMd5 = @"";
// append.contentEncoding = @"";
// append.contentDisposition = @"";
OSSTask * appendTask = [client appendObject:append];
[appendTask continueWithBlock:^id(OSSTask *task) {
NSLog(@"objectKey: %@", append.objectKey);
if (!task.error) {
NSLog(@"append object success!");
OSSAppendObjectResult * result = task.result;
NSString * etag = result.eTag;
long nextPosition = result.xOssNextAppendPosition;
} else {
NSLog(@"append object failed, error: %@" , task.error);
}
return nil;
}];
上傳後回調通知
用戶端在上傳Object時可以指定OSS服務端在處理完上傳請求後,通知您的商務服務器,在該伺服器確認接收了該回調後將回調的結果返回給用戶端。因為加入了回調請求和響應的過程,相比簡單上傳,使用回調通知機制一般會導致用戶端花費更多的等待時間。
具體說明參考:Callback
程式碼範例:
OSSPutObjectRequest * request = [OSSPutObjectRequest new];
request.bucketName = @"<bucketName>";
request.objectKey = @"<objectKey>";
request.uploadingFileURL = [NSURL fileURLWithPath:@<filepath>"];
// 設定回調參數
request.callbackParam = @{
@"callbackUrl": @"<your server callback address>",
@"callbackBody": @"<your callback body>"
};
// 設定自訂變數
request.callbackVar = @{
@"<var1>": @"<value1>",
@"<var2>": @"<value2>"
};
request.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};
OSSTask * task = [client putObject:request];
[task continueWithBlock:^id(OSSTask *task) {
if (task.error) {
OSSLogError(@"%@", task.error);
} else {
OSSPutObjectResult * result = task.result;
NSLog(@"Result - requestId: %@, headerFields: %@, servercallback: %@",
result.requestId,
result.httpResponseHeaderFields,
result.serverReturnJsonString);
}
return nil;
}];
分區上傳
因為篇幅的原因,分區上傳參考:分區上傳
斷點續傳
特別注意:
斷點續傳暫時只支援上傳本地檔案。
對於移動端來說,如果不是比較大的檔案,不建議使用這種方式上傳,因為斷點續傳是通過分區上傳實現的,上傳單個檔案需要進行多次網路請求,效率不高。**
在無線網路下,上傳比較大的檔案期間長,可能會遇到因為網路條件差、使用者切換網路等原因導致上傳中途失敗,整個檔案需要重新上傳。為此,SDK提供了斷點上傳功能。
在上傳前,可以指定斷點記錄的保存檔案夾。若不進行此項設定,斷點上傳只在本次上傳生效,某個分區因為網路原因等上傳失敗時會進行重試,避免整個大檔案重新上傳,節省重試時間和耗用流量。如果設定了斷點記錄的保存檔案夾,如果任務失敗,在下次重新啟動任務,上傳同一檔案到同一Bucket、Object時,如果使用者佈建取消時不刪除斷點記錄。再次上傳將從斷點記錄處繼續上傳。詳見隨後的範例。
斷點續傳失敗時,如果同一任務一直得不到續傳,可能會在OSS上積累無用碎片。對這種情況,可以為Bucket設定lifeCycle規則,定時清理碎片。參考:生命週期管理。
出於碎片管理的原因,如果在斷點續傳時取消當前任務。預設會同步清理已經上傳到伺服器的分區。如果取消時需要保留斷點上傳記錄,需要指定斷點記錄的保存檔案夾並修改deleteUploadIdOnCancelling參數。需要注意,如果本地保留記錄時間過長,且Bucket設定lifeCycle規則定時清理了服務端分區。會出現服務端和移動端記錄不一致的問題。
說明:
斷點續傳的實現依賴
InitMultipartUpload/UploadPart/ListParts/CompleteMultipartUpload/AbortMultipartUpload
,如果採用STS鑒權模式,請注意加上這些API所需的許可權。斷點續傳也支援上傳後回調通知,用法和上述普通上傳回調通知一致。
斷點續傳已經預設開啟每個分區上傳時的Md5校驗,請勿重複在request中設定
Content-Md5
頭部。
在本地持久保存斷點記錄的調用方式(預設是不設定):
OSSResumableUploadRequest * resumableUpload = [OSSResumableUploadRequest new];
resumableUpload.bucketName = OSS_BUCKET_PRIVATE;
//...
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
resumableUpload.recordDirectoryPath = cachesDir;
斷點續傳功能實現
// 獲得UploadId進行上傳,如果任務失敗並且可以續傳,利用同一個UploadId可以上傳同一檔案到同一個OSS上的儲存物件
OSSResumableUploadRequest * resumableUpload = [OSSResumableUploadRequest new];
resumableUpload.bucketName = <bucketName>;
resumableUpload.objectKey = <objectKey>;
resumableUpload.partSize = 1024 * 1024;
resumableUpload.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
//設定斷點記錄檔案
resumableUpload.recordDirectoryPath = cachesDir;
//設定NO,取消時,不刪除斷點記錄檔案,如果不進行設定,預設YES,是會刪除斷點記錄檔案,下次再進行上傳時會重新上傳。
resumableUpload.deleteUploadIdOnCancelling = NO;
resumableUpload.uploadingFileURL = [NSURL fileURLWithPath:<your file path>];
OSSTask * resumeTask = [client resumableUpload:resumableUpload];
[resumeTask continueWithBlock:^id(OSSTask *task) {
if (task.error) {
NSLog(@"error: %@", task.error);
if ([task.error.domain isEqualToString:OSSClientErrorDomain] && task.error.code == OSSClientErrorCodeCannotResumeUpload) {
// 該任務無法續傳,需要獲取新的uploadId重新上傳
}
} else {
NSLog(@"Upload file success");
}
return nil;
}];
// [resumeTask waitUntilFinished];
// [resumableUpload cancel];
資料完整性校驗
因為移動端網路環境的複雜性,OSS SDK提供了基於MD5和CRC64的端到端的資料完整性驗證功能。
MD5校驗
需要在上傳檔案時提供檔案的Content-MD5值,OSS伺服器會幫助使用者進行MD5校驗,只有在OSS伺服器計算已接收的檔案得到的MD5值和上傳提供的MD5一致時才可以上傳成功,從而保證上傳資料的完整性。
OSSPutObjectRequest * request = [OSSPutObjectRequest new];
request.bucketName = BUCKET_NAME;
...
request.contentMd5 = [OSSUtil fileMD5String:filepath];
CRC校驗
與MD5相比,CRC64可以同時上傳並計算CRC值。
// 構造上傳請求
OSSPutObjectRequest * request = [OSSPutObjectRequest new];
request.bucketName = OSS_BUCKET_PRIVATE;
///....
request.crcFlag = OSSRequestCRCOpen;
// 開啟crc效驗後。如果在傳輸中資料不一致,會提示OSSClientErrorCodeInvalidCRC 錯誤。
OSSTask * task = [_client putObject:request];
[[task continueWithBlock:^id(OSSTask *task) {
//如果crc效驗失敗,會有error
XCTAssertNil(task.error);
return nil;
}] waitUntilFinished];