React Native using pre-signedurl。からS3に画像をアップロードしようとして運が悪かった。私のコードは次のとおりです。
ノードで事前署名されたURLを生成します。
const s3 = new aws.S3();
const s3Params = {
Bucket: bucket,
Key: fileName,
Expires: 60,
ContentType: 'image/jpeg',
ACL: 'public-read'
};
return s3.getSignedUrl('putObject', s3Params);
これがS3へのRNリクエストです:
var file = {
uri: game.pictureToSubmitUri,
type: 'image/jpeg',
name: 'image.jpg',
};
const xhr = new XMLHttpRequest();
var body = new FormData();
body.append('file', file);
xhr.open('PUT', signedRequest);
xhr.onreadystatechange = () => {
if(xhr.readyState === 4){
if(xhr.status === 200){
alert('Posted!');
}
else{
alert('Could not upload file.');
}
}
};
xhr.send(body);
game.pictureToSubmitUri = assets-library://asset/asset.JPG?id=A282A2C5-31C8-489F-9652-7D3BD5A1FAA4&ext=JPG
signedRequest = https://my-bucket.s3-us-west-1.amazonaws.com/8bd2d4b9-3206-4bff-944d-e06f872d8be3?AWSAccessKeyId=AKIAIOLHQY4GAXN26FOQ&Content-Type=image%2Fjpeg&Expires=1465671117&Signature=bkQIp5lgzuYrt2vyl7rqpCXPcps%3D&x-amz-acl=public-read
エラーメッセージ:
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided. Check your key and signing method.
</Message>
生成されたURLを使用してS3に正常にカールして画像を作成でき、RNからrequestb.inに正常に投稿できるようです(ただし、requestb.inの生データしか表示できないため、画像が適切であるかどうかを100%確認することはできません。そこ)。
これらすべてに基づいて、問題を1)画像が正しくアップロードされていない期間、または2)S3がリクエストを要求する方法が受信方法と異なることに絞り込みました。
どんな助けでもmuuuuuucchhhhに感謝します!
更新
本文が単なるテキスト({'data': 'foo'})の場合、RNからS3に正常に投稿できます。おそらくAWSはマルチフォームデータが好きではありませんか? RNでファイルとして送信するにはどうすればよいですか?
FormData
はmultipart/form-data
リクエストを作成します。 S3 PUT
オブジェクトは、リクエスト本文がファイルである必要があります。
ファイルをFormData
にラップせずに、リクエスト本文で送信する必要があります。
function uploadFile(file, signedRequest, url) {
const xhr = new XMLHttpRequest();
xhr.open('PUT', signedRequest);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if(xhr.status === 200) {
alert(url);
} else {
alert('Could not upload file.');
}
}
};
xhr.send(file);
};
たとえば、ブラウザで https://devcenter.heroku.com/articles/s3-upload-node を参照してください。また、Content-Type
ヘッダーが署名付きURLリクエストと一致していることを確認してください。
IOSとAndroidの両方で事前に署名されたS3URLにアップロードするのに多くの時間を無駄にしました。私のために働いたのは rn-fetch-blob lib
コードスニペット:
import RNFetchBlob from 'rn-fetch-blob'
const preSignedURL = 'pre-signed url'
const pathToImage = '/path/to/image.jpg' // without file:// scheme at the beginning
const headers = {}
RNFetchBlob.fetch('PUT', preSignedURL, headers, RNFetchBlob.wrap(pathToImage))