Reputation: 429
I have a static website hosted on AWS S3. The website can be accessed from either: https://s3.amazonaws.com/example-bucket-name-to-avoid-spam/index.html Or http://example-bucket-name-to-avoid-spam.s3-website-us-east-1.amazonaws.com/
When a user completes the form and the captcha on the page and presses submit the following JavaScript is triggered:
<script>
// Replace the YOUR_API_ENDPOINT_URL with yours
// It should look something like this:
// https://qw324asdasd.execute-api.us-east-1.amazonaws.com/dev/api/sendSms
const API_ENDPOINT = 'https://fak3ur1.execute-api.us-east-1.amazonaws.com/dev/api/sendSms';
var messageDiv = document.getElementById('error-message')
// Handle public api call
document.getElementById('send-text').addEventListener('click', function () {
const captchtaResponse = grecaptcha.getResponse() || false
const textMessage = document.getElementById('message').value
const phoneNumber = document.getElementById('phone-number').value
if (!textMessage) {
messageDiv.innerHTML = 'Remember to enter a message!'
return false
}
if (!phoneNumber) {
messageDiv.innerHTML = 'Don\'t forget to enter a phone number!'
return false
}
if (!captchtaResponse) {
messageDiv.innerHTML = 'Complete the Captcha please!'
return false
}
const data = JSON.stringify({
to: phoneNumber,
message: textMessage,
captcha: captchtaResponse
})
// post to API with native browser Fetch
const getdata = fetch(API_ENDPOINT, {
headers: {
"Content-type": "application/json"
},
method: 'POST',
body: data,
mode: 'cors',
cache: false,
});
getdata.then(function(response) {
response.json().then(function(data) {
console.log('Response:', data);
const body = JSON.parse(data.body);
messageDiv.textContent = '';
messageDiv.textContent = (body && body.message) ? body.message : '';
});
}).catch(function(err) {
console.log(err)
});
});
</script>
This successfully sends a POST through to the AWS API Gateway which processes the request correctly and sends a text with Twilio to the desired phone number.
I've also confirmed in Postman that the API Gateway/Lambda response itself is correctly coming back:
{
"statusCode": 200,
"headers": {
"Access-Control-Allow-Origin": "*"
},
"body": "{\"message\":\"Text message successfully sent!\",\"data\":{\"dateCreated\":\"2017-07-06T16:49:00.000Z\",\"dateUpdated\":\"2017-07-06T16:49:00.000Z\",\"from\":\"+13334445566\",\"body\":\"Sent from your Twilio trial account - test 5 with postman - looking at Lambda logs\"}}"
}
The issue happens after that POST is (presumably) sent to API Gateway. The static site redirects to an error page with this message when on the non-https url above:
405 Method Not Allowed
Code: MethodNotAllowed
Message: The specified method is not allowed against this resource.
Method: POST
ResourceType: OBJECT
RequestId: IDSTRING123
HostId: Longhostidthing1237ygausdhasdgylh231ctidasd=
And this for the https url:
<Error>
<Code>MethodNotAllowed</Code>
<Message>
The specified method is not allowed against this resource.
</Message>
<Method>POST</Method>
<ResourceType>OBJECT</ResourceType>
<RequestId>IDSTRING123</RequestId>
<HostId>
Longhostidthing1237ygausdhasdgylh231ctidasd=
</HostId>
</Error>
Initially I thought this was a CORS issue, but I've checked and rechecked several times the CORS policy on the bucket is very permissive:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<MaxAgeSeconds>0</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>0</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
I've also fiddled around with this a few times to confirm I was being as permissive as possible.
Finally, I've tried this incognito in Chrome, with cookies and all browsing data cleared in a separate profile, and all of the above with a plugin that disables CORS from the browser-side. None of these attempts appear to resolve my issue.
Any ideas?
Upvotes: 3
Views: 3338
Reputation: 429
Mark B was correct.
"It sounds like you are posting something via JavaScript to API Gateway, but then also posting the same thing to S3? My guess is you need to simply prevent the default form post action from occurring since you are handling it via javascript."
Edit: The easiest fix for this is to change this line:
document.getElementById('send-text').addEventListener('click', function () {
to this:
document.getElementById('send-text').addEventListener('click', function (event) {
And call event.preventDefault()
on the subsequent line to prevent the default code from running and firing a post request.
Upvotes: 2