As in the title, I can get a pre-signed URL from lambda with no issue. The URL works in cURL to upload an image without any issue, and also works with a test python script.
I cannot for the life of me figure out why this isn't working in javascript (React Native specifically, in Expo).
Here's roughly the code of interest:
const getBlob = async (fileUri) => {
const resp = await fetch(fileUri);
const imageBody = await resp.blob();
return imageBody;
};
async function putPhoto(photoURI){
// code to get the S3URL
const imageBlob = await getBlob(photoURI)
response = await fetch(S3URL,{
method: "PUT",
body: imageBlob,
// headers: {
// "Content-Type": "application/json"
// }
})
It's especially maddening since the response from S3 includes the URL, which I can explicitly cURL to and successfully resolve:
curl -X PUT -T .\test.jpg "https://<bucketname>.s3.amazonaws.com/<lambda generated hash>.jpg?AWSAccessKeyId=<>&x-amz-security-token=<>&Expires=<>"
With of course 'sensitive data' being replaced in <>.
The only things I can see that others have had common issues with is on the headers - of which I've also tried entering:
headers: {}
As I would assume that would override any global scope of headers I'm forgetting about.
Any tips? Much appreciated.
Ok, looks like S3 is very specific about needing a the right header when getting a fetch() request and doesn't care about those same headers from a cURL. Or at least, needs to be set up as such for fetch in this case.
Python code for lambda:
url = boto3.client('s3').generate_presigned_url(
ClientMethod='put_object',
Params={'Bucket': BUCKET_NAME, 'Key': full_id, 'ContentType': 'application/octet-stream'},
ExpiresIn=3600
)
Critical to add the Content-Type param as shown.
Also, change my code above to (see Content-Type):
async function putPhoto(photoURI){
// code to get the S3URL
const imageBlob = await getBlob(photoURI)
response = await fetch(S3URL,{
method: "PUT",
body: imageBlob,
headers: {
"Content-Type": "application/octet-stream"
}
})