1

我想從我的iPhone應用程序上傳圖像到S3,然後將S3網址存回我的Rails應用程序。我不應該嵌入在iOS應用憑據所以我採取的辦法是:使用預先簽署的S3網址使用AFNetworking從iOS應用程序上傳

我盡了最大努力去遵循我在網上找到的所有方向,但它不工作,第3步的結果返回了錯誤401禁止。既然我是這個新手,我甚至不知道自己做錯了什麼。

在步驟2中,我的代碼看起來是這樣的:

def getS3Url 
    s3 = AWS::S3.new(
    :access_key_id => "MY S3 KEY", 
    :secret_access_key => "MY SECRET ACCESS KEY" 
) 
    object = s3.buckets[params["bucket"]].objects[params["path"]] 
    @s3url = object.url_for(:write, { :expires => 20.minutes.from_now, :secure => true }).to_s 
end 

的網址從第二步返回看起來是這樣的:https://s3.amazonaws.com/myapp-bucket-name/images/avatar/user1.png?AWSAccessKeyId=[access key id]&Expires=[expiration timestamp]&Signature=[Signature]

而且一旦我得到URL我嘗試做對它發帖以下內容:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 
[manager POST:[responseObject valueForKey:@"s3url"] parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { 
    [formData appendPartWithFileData:jpegData name:@"file" fileName:self.filename mimeType:@"image/png"]; 
} success:^(AFHTTPRequestOperation *operation, id responseObject) { 
    NSLog(@"Success: %@", responseObject); 
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
    NSLog(@"Error: %@", error); 
}]; 

在這段代碼中我從[responseObject valueForKey:@"s3url"]返回的對象中提取出來的URL,然後傳遞作爲URL發佈。但它不起作用。下面是當我在XCode中運行它日誌:

錯誤:錯誤域= AFNetworkingErrorDomain代碼= -1011 「請求失敗:禁止(403)」 的UserInfo = 0x156daaf0 {NSErrorFailingURLKey = https://s3.amazonaws.com/myapp-bucket-name/images/avatar/user1.png?AWSAccessKeyId=[access密鑰ID] &到期= [到期時間戳] & Signature = [Signature],NSLocalizedDescription = Request failed:forbidden(403),NSUnderlyingError = 0x156aef90「Request failed:unacceptable content-type:application/xml」,AFNetworkingOperationFailingURLResponseErrorKey = {URL:https://s3.amazonaws.com/myapp-bucket-name/images/avatar/user1.png?AWSAccessKeyId=[access key id] & Expires = [expiration timestamp] &簽名= [簽名]} {狀態碼:403,標題{0}連接=關閉; 「Content-Type」=「application/xml」; Date =「Mon,30 Jun 2014 07:21:33 GMT」; 服務器= AmazonS3; 「Transfer-Encoding」=身份; 「x-amz-id-2」=「FJwEeOjV1/osJKgKeHO +/OjXVBEbvW09XxNX2kn1UYIuHswU + LKh0mJODRJDNLXm」; 「x-amz-request-id」= 46E84D0967B6D4CD; }}}

在這一點上,我甚至不知道我做錯了什麼。也許我甚至沒有發佈到正確的網址。也許我需要做的不僅僅是POST。我花了整個週末試圖弄清楚這個並且失敗了。有人可以幫忙嗎?謝謝。

+0

@Viad,你有沒有找到任何解決方案,我有相同的錯誤,我也發現你的線程https://forums.aws.amazon.com/thread.jspa?threadID=155506 – Abhishek

回答

6

我面臨類似的「挑戰」。我必須使用AFNetworking 2.0將映像上傳到帶有來自我的服務器的預簽名URL的S3存儲桶。在做我的許多嘗試和錯誤的嘗試之一,我得到了同樣的403錯誤,併發生了什麼事我是,我不得不把正確的頭在請求:

  • Content-Type的MIME類型圖像
  • x-amz-acl作爲public-read我區段配置

內容長度似乎是可選的,請注意,我沒有上傳在多圖像。

所以這是我落得這樣做:

+(void) uploadImage:(UIImage *)image atUrl:(NSString *)url withMimeType:(NSString *)mimeType withSuccess:(void (^)(id responseObject))success failure:(void (^)(NSError *error))failure { 
    NSData *imageData = UIImageJPEGRepresentation(image, 0.1); 
    NSURL *requestURL = [NSURL URLWithString:url]; 
    AFHTTPSessionManager *client = [[AFHTTPSessionManager alloc] initWithBaseURL:requestURL]; 
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; 
    [request setHTTPMethod:@"PUT"]; 
    [request setValue:mimeType forHTTPHeaderField:@"Content-Type"]; 
    [request setHTTPBody:imageData]; 
    [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[imageData length]] forHTTPHeaderField:@"Content-Length"]; 
    [request setValue:@"public-read" forHTTPHeaderField:@"x-amz-acl"]; 
    [request setURL:requestURL]; 

    NSURLSessionDataTask *task = [client dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { 
     if (error == nil) { 
      if (success) { 
       success(responseObject); 
      } 
     } else { 
      if (failure) { 
       failure(error); 
      } 
     } 
    }]; 
    [task resume]; 
} 

其中URL是,我已經從我的服務器得到了presigned網址。檢查我在0.1時的JPEG壓縮,因爲您可能需要不同的壓縮。在我的情況下,圖像質量並不重要。

1

添加到上述josebama的回答,

我沒有需要添加 「X-AMZ-ACL」 頭字段,而是我加 「X-AMZ-日期」 和 「授權」 標頭。這兩個標題都是從處理與Amazon服務通信的API以及簽名URL返回的。當我添加上述兩個標題值時,上傳到URL只是成功的。

在我的情況下,只包含「x-amz-acl」標題將導致上傳失敗。

也許某些服務器端參數不同,或者某些亞馬遜的設置參數可能有所不同,不用說對我有用的解決方案可能不適用於其他服務器,所以稍微查看後端設置可能不錯。

相關問題