9

署名付き URL を使用して、iOS アプリから AWS S3 バケットにファイルをアップロードしたいと考えています。コマンド ラインで curl を使用するため、URL は正しいです。

curl -v -k --upload-file FILENAME "https://MYBUCKET.amazonaws.com:443/KEYNAME?Signature=...&Expires=1391691489&AWSAccessKeyId=..."

次のObjective-Cコードで...

- (void)upload:(NSString *)url fileData:(NSData *)fileData
{
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"PUT"];
    [request setHTTPBody:fileData];
    [request setValue:[NSString stringWithFormat:@"%d", [fileData length]] forHTTPHeaderField:@"Content-Length"];
    [request setValue:@"audio/mpeg" forHTTPHeaderField:@"Content-Type"];
    [request setValue:@"public-read" forHTTPHeaderField:@"x-amz-acl"];
    [request setValue:@"iPhone-OS/6.0 fr_FR NE" forHTTPHeaderField:@"User-Agent"];

    _connection = [NSURLConnection connectionWithRequest:request delegate:self];
    [_connection start];
}

...次のエラーが表示されます。

Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0x9c49560 {NSErrorFailingURLStringKey=https://MYBUCKET.s3.amazonaws.com:443/KEYNAME?Signature=...&Expires=1391703958&AWSAccessKeyId=..., NSErrorFailingURLKey=https://MYBUCKET.amazonaws.com:443/KEYNAME?Signature=...&Expires=1391703958&AWSAccessKeyId=..., NSLocalizedDescription=The request timed out., NSUnderlyingError=0x9c48c80 "The request timed out."}

WireShark を使用して、トラフィックがあるかどうか、トラフィックが多いかどうかを確認しました。

コードの何が問題なのかわかりません。ファイル転送が正しく終了していないようです。

4

1 に答える 1

11

私はこれを自分で解決しました。Content-Typeヘッダーが原因でした。完全に絶望して、非常に小さなテキスト ファイルでコードをテストしたところ、S3 からの HTTP ステータス コードとして 403 が返されました。タイムアウトなし。そんな進歩。また、非常に有益なエラー メッセージも表示されました。

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><StringToSignBytes>...</StringToSignBytes><RequestId>...</RequestId><HostId>...</HostId><SignatureProvided>...</SignatureProvided>
    <StringToSign>PUT

    text/plain
    1391784394
    KEYNAME</StringToSign>
    <AWSAccessKeyId>...</AWSAccessKeyId>
</Error>

明らかに、クライアントから HTTP ヘッダーとして提供される場合、コンテンツ タイプ文字列 (text/plainこの場合) は署名対象文字列で期待されます。大きなファイル (5.5MB?)でタイムアウトが発生する理由を聞かないでください。これが他の誰かの数時間を節約できることを願っています。

最も簡単な修正は、行を削除することです

[request setValue:@"..." forHTTPHeaderField:@"Content-Type"];

事前に署名された URL を作成するときにコンテンツ タイプがわかっている場合は、もちろんその文字列を署名する文字列に追加できます。

于 2014-02-07T14:52:01.430 に答える