How to configure AWS S3 to allow POST to work like GET
Asked Answered
F

3

5

Facebook states in their canvas setup documentation:

Our servers will make an HTTP POST request to this web address. The retrieved result will be displayed within the Canvas frame on Facebook.

My application is hosted on AWS S3 as a static website using the following CORS configuration:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

Already I'm having an issue here. GET requests work perfectly, but POSTing to http://my-bucket-name.s3-website-us-east-1.amazonaws.com kicks back:

<html>
    <head>
        <title>405 Method Not Allowed</title>
    </head>
    <body>
        <h1>405 Method Not Allowed</h1>
        <ul>
            <li>Code: MethodNotAllowed</li>
            <li>Message: The specified method is not allowed against this resource.</li>
            <li>Method: POST</li>
            <li>ResourceType: OBJECT</li>
            <li>RequestId: 94159551A72424C7</li>
            <li>HostId: +Lcz+XaAzL97Y47OZFvaTwqz4Z7r5koaJGHjZJBBMOTUHyThTfKbZG6IxJtYEbtsXWcb/bFxeI8=</li>
        </ul>
        <hr/>
    </body>
</html>

Step 1: ^ I think I need to get this this working.

but wait, there's more

Facebook also requires a secure url. so for this, I went to cloudfront.

My configuration looks like this:

Cloudfront Configuration

More Cloudfront Configuration

Just like when working with S3 directly, making GET requests to https://app-cloudfront-id.cloudfront.net/ works like a champ, POSTing, kicks back this:

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>MethodNotAllowed</Code>
    <Message>The specified method is not allowed against this resource.</Message>
    <Method>POST</Method>
    <ResourceType>OBJECT</ResourceType>
    <RequestId>657E87A80AFBB3B0</RequestId>
    <HostId>SY2g4smvhr06kAAQYVMsYeQZ+pSKbIIvsh/OaPBiMADGt5UKut0sXSZkFsnFmcRXQ2PFBVgPK4M=</HostId>
</Error>

Viewing the app on facebook.com shows:

app on facebook

Am I missing something?

Furnary answered 4/4, 2016 at 13:42 Comment(5)
This is not a CORS issue – Facebook makes the POST request to your app by submitting a hidden form, it does not request your URL via AJAX.Imeldaimelida
@CBroe I'm almost certain it's a CORS issue. AWS is rejecting POST requests, whether I make them through a REST client, or by visiting the facebook page (see the screenshot I added - also, apologies for my XML plugin making that look weird in the screenshot)Furnary
“AWS is rejecting POST request” – and that is why it is not a CORS issue. (CORS would only come into play if your browser was making cross-domain requests via JS – and in that case, the browser would refuse to make the request, if the remote endpoint was not CORS-enabled. What you have here however is the server saying, “POST? I don’t know what to do with that.”) https://mcmap.net/q/1692231/-amazon-s3-405-method-not-allowed-using-post-although-i-allowed-post-on-the-bucketImeldaimelida
@CBroe that makes sense. thank you for clearing that up. Do you know if it's possible for S3 to respond to POST as it it were GET? (or perhaps Cloudfront?)Furnary
My understanding is that S3 is exactly that - static documents. There's nothing there that can 'action' a post - Surely you need a web server for that? It's like trying to post to a file shareLatanya
D
6

so - I too thought this should be easy and well supported by AWS in 2016. Apparently, from all the reading I've done, we're wrong.

There's no way to serve the index page for a facebook app from s3 - with or without cloudfront.

It might be possible to serve the index page from an alternate origin (ie, your own httpd running somewhere) through cloudfront and everything else from s3 - but I haven't tried to dig into that rabbit hole. And if you're still having to run your own HA httpd...the complexity might not be worth it depending on your asset scale. ie http://www.bucketexplorer.com/documentation/cloudfront--how-to-create-distributions-post-distribution-with-multiple-origin-servers.html

you -can- use cloudfront in front of your own origin httpd serving the static content to take advantage of the cache and edge distribution - it will just forward the POST (and PUT etc) to your origin and bypass the cache edge.

these answers are old, circa 2011, - but I can't find any evidence that anything has changed with this.

https://forums.aws.amazon.com/thread.jspa?messageID=228988&#228988

https://forums.aws.amazon.com/thread.jspa?threadID=62525

Hopefully we can get some activity on this thread to prove me wrong, I could use this right now too.

Dennisedennison answered 5/4, 2016 at 17:37 Comment(3)
This is also the conclusion I have come to. FWIW: Here is a nasty workaround that I'm using: webmasterymadesimple.com/blog/…Furnary
haha, that's not entirely a bad hack - though you'd have worry about the impact of bitly's rate limiting for requests if you have any sort of traffic at scale.Dennisedennison
It's 2018 and I had the same question. Absent any specific documentation from AWS, I presume you can't POST to a static website because, it is supposedly static. If you wanted to process any input - like the semantics of POST would suggest - you'd have to to run a server to handle the incoming data making the server not "static".Sizable
W
3

I have a similar situation, using a single-page JS application, where all unresolved requests normally should be handled main page, /index.html.

The underlying problem is that S3 does not treat a POST like a GET. POST is a modifying request. There is a way to configure S3 to handle the POST, but that is intended for S3 modifications, not a read-only request like GET.

In order to handle the POST requests, I created an AWS CloudFront behavior that redirects the errors back to /index.html with a 200 HTTP response code. That way the POST request will go to the main page, and managed through the application. I have done the same thing for the 403 and 404 errors.

AWS CloudFront Error Page Configuration

Edit the CloudFront distribution, go Error Pages, and create 3 different custom error responses as shown above.

FYI, you can easily add a dynamic side via CloudFront, avoiding all CORS issues. CloudFront can mix both static and dynamic content through the behaviors.

Wilmott answered 30/4, 2020 at 15:49 Comment(1)
I went crazy running behind this issue for half a day. This worked like a charm!Immitigable
I
0

Try creating the page as a response object to a Lambda function and use the ApiGateway to create a route to handle the page processing.

Leave the static content on S3, CloudFront for the SSL support and Lambda for any dynamic page processing.

Imprecation answered 12/11, 2017 at 17:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.