302 Redirect in AWS Cloudfront - amazon-web-services

I have a webstack that is currently serving both dynamic and static content. I want start serving the static content from AWS CloudFront without having to change all of the urls.
So I set up CloudFront to serve the static content from AWS S3 and the dynamic content from a custom url (current webstack). This worked however CloudFront was making the request to our webstack via a rewrite rule.
Is it possible for CloudFront to return a 302 redirect so that the request to my webstack would come from the users browser?
Unfortunately this is critical for our application to work properly.

I don't think it's possible, because CloudFront should follow 302 redirects and cache the result, rather than return the 302 redirect to the client.

Related

How to handle 403 and 404 errors with AWS Cloudfront containing multiple origins

I have the current configuration in AWS:
S3 Bucket set to static website for my frontend
ELB which has an EC2 instance for my backend
Cloudfront distribution with two origins, two behaviors, and two custom error pages
Origins:
S3 Bucket (static website)
dev-api.mydomain.com (ALIAS record mentioned below that points to ELB)
Behaviors:
"/api/*" routes to dev-api.mydomain.com
"*" routes to S3
Error pages (this part is the most important to my question):
403 returns 200 response with index.html (which comes from S3)
404 returns 200 response with index.html (which comes from S3)
Route53:
registered domain
dev.mydomain.com points to cloudfront distribution
dev-api.mydomain.com points to ELB
How do I distinguish between the 403 and 404 errors that come back from my S3 and backend server?
Note: I am using react router to handle all routing in the static website so every request to S3 would return a 404 from S3 unless the user specifically asked for the /index.html resource.
Scenario 1: When a user goes to dev.mydomain.com/logi (mispelled login), I would expect that to hit my S3 bucket and return with a 404 which would then fetch the index.html file in the bucket. Cloudfront would return the index.html file with a 200 OK Status and my application would handle the invalid route by displaying a 404 page.
Scenario 2: When a user goes to dev.mydomain.com/login, it would hit my S3 bucket, return with a 404 and return the index.html file. Once I land on the login page, for this examples sake, I fire off a network request to dev.mydomain.com/api/non_existant_route. I would expect that to hit my API server and return with a 404 which my frontend would then handle by displaying an error message about the API request failing.
However what is happening in Scenario 2 is that a 404 is returned from my backend server to Cloudfront, which then returns the index.html file (from S3) as the response with a 200 status code.
So, my question is - Is it possible to configure Cloudfront to return different error pages based on the origin that is sending back the error code? If not, how can I accomplish returning the correct response for the backend server?
Would it require me to re-architect my AWS solution?
Another way is to:
turn on Static Web Hosting on S3
replace the S3 bucket name in CloudFront origin with the S3 Static Website URL.
remove Error Pages from CloudFront.
The error pages will be handled by the respective origins instead of CloudFront.
I was able to solve the 403 and 404 issues by removing Custom Error responses from cloudfront.
I created a Lambda#Edge function on the default behavior (*) which routes to my S3 bucket. On Origin Request, the function modifies requests to pages like /login to instead return /index.html from the bucket.
In my case, I also have two origins and both are one page app (OPA) so both contains index.js
React App (Responsible for my main application) hosted through S3 static website. (CSR build)
Webflow App (Static website for product info and blog, etc..)
Our react app has many different behaviours based on routes (application need), so I configured Webflow as default behaviour.
First, I added custom error handling for 404 with redirect page path to /index.js and HTTP Status 200, as many app routes are not directly present in S3 Website and result into 404 (This is suggested by many tech blog and works very well in case of single origin)
But as soon as I added Webflow website origin as my Default(*) behaviour, whenever 404 occurs in React app it will get redirected to default behaviours /index.js (Our static product info website)
Finally, I removed all custom error handling and it will start working as expected. All the React routes are redirecting to React behaviours and not matching behaviour routes are going to Default(*) Webflow website.

Will amazon-cloudfront follow a 308 redirect?

I am working on setting up amazon cloud front and have been playing around with the cache-control settings. It is explicitly stated here, that amazon-cloudfront will not follow a 301 and 307.
I am wondering if there is documentation on if the redirect will be followed if the origin returns a 308?
It seems a little strange that 302 and 308 are not mentioned, here, but CloudFront does not follow redirects. They are stored in the cache and returned to the browser.
You can intercept redirects with a Lambda#Edge response trigger, but the typical application for this is to rewrite the Location header and send the browser somewhere other than where it would otherwise have gone.
For small responses, it's possible to actually follow the redirect using an Origin Response trigger that makes a request using the Node HTTP client, but this only suports responses up to 1 MB in total size, and would probably not perform as well as simply letting the browser follow the redirect.
There is some additional documentation here of handling redirects:
If you change the location of an object on the origin server, you can
configure your web server to redirect requests to the new location.
After you configure the redirect, the first time a viewer submits a
request for the object, CloudFront Front sends the request to the
origin, and the origin responds with a redirect (for example, 302
Moved Temporarily). CloudFront caches the redirect and returns it to
the viewer. CloudFront does not follow the redirect.
You can configure your web server to redirect requests to one of the
following locations:
The new URL of the object on the origin server. When the viewer follows the redirect to the new URL, the viewer bypasses CloudFront
and goes straight to the origin. As a result, we recommend that you
not redirect requests to the new URL of the object on the origin.
The new CloudFront URL for the object. When the viewer submits the request that contains the new CloudFront URL, CloudFront gets the
object from the new location on your origin, caches it at the edge
location, and returns the object to the viewer. Subsequent requests
for the object will be served by the edge location. This avoids the
latency and load associated with viewers requesting the object from
the origin. However, every new request for the object will incur
charges for two requests to CloudFront.
But because 301 and 308 only difference is that 308
does not allow changing the request method from POST to GET
i would guess that it is handled like 301.
The documentation has since original post been updated to include info on 301, 302, 304, 307 and 308.

Static site hosted on S3 and Cloudfront root page routes to www.example.com/index.html, not www.example.com

I have a static site hosted on Amazon S3 and Cloudfront.Currently, when I go to my site, www.example.com, I get a 403. It's only when I go to www.example.com/index.html that I actually access my site. My desired behavior is that when I go to www.example.com, I see what I see when I go to www.example.com/index.html.
I've set up a bucket that we can call example.com, that contains all of my site's information. I also have another bucket (www.example.com) that redirects to example.com.
My domain points to Cloudfront, where I have a Cloudfront domain set. I think this is where the problem is. I have to go to /index.html from this domain to actually see the site.
How do I set this up so that when I go to www.example.com, I see what currently lives at www.example.com/index.html?
I have already set index.html as my bucket's Index document.
CloudFront's default root object only works for the root of your domain. So a request to https://example.com will serve /index.html from S3, but a request to https://example.com/about-us will simply 404 (or 403, depending on permissions).
If you want to serve index.html from any directory, you need to deploy a Lambda#Edge function for the origin request. Follow this tutorial, and the function body you need (Node.js 8.10) is:
exports.handler = (event, context, callback) => {
const { request } = event.Records[0].cf;
const parts = request.uri.split('/');
const lastPart = parts[parts.length - 1];
const hasExtension = lastPart.includes('.');
if (!hasExtension) {
const newURI = request.uri.replace(/\/?$/, '/index.html');
request.uri = newURI;
}
return callback(null, request);
};
When you setup your S3 bucket for static website hosting (with or without CloudFront), you can configure the bucket with an Index Document. The Index Document is sent to the client when the client makes a directory request.
For example, you want www.example.com/index.html to be served when the client goes to www.example.com.
To do this, set index.html as your bucket's Index Document.
https://docs.aws.amazon.com/AmazonS3/latest/dev/HostingWebsiteOnS3Setup.html
See Step 1, sub-step 3(b).
In the CloudFront general configuration settings make sure the default root object is set to index.html. As a best practice you should use an Origin Access Identifier to ensure your objects are only served through CloudFront.
Also make sure your origin is set properly to your S3 bucket and the folder that contains your site (if applicable).

AWS CloudFront CORS Support

I am trying to build an app where users upload content on their browsers to an S3 bucket through CloudFront. I have enabled CORS on the S3 bucket and ensured that the AllowedOrigin is set to *. I can successfully push content from a browser to the S3 bucket directly so I know that CORS on S3 is configured correctly. Now, I am trying to do the same with browser -> CloudFront -> S3. CloudFront always rejects the pre-flight OPTIONS method request with a 403 forbidden response.
I have the following options enabled on CloudFront:
Allowed HTTP Methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
Whitelist Headers: Access-Control-Request-Headers,
Access-Control-Request-Method, Origin OPTIONS requests are disabled
from the "Cached HTTP Methods"
CloudFront apparently now supports CORS but has anyone got it working for an HTTP method OPTIONS request? I tried asking this on the AWS forums but no responses.
Have your try adding a CNAME alias for your cloudfront domain ??
After setting up the CNAME alias, you can set the cookies on the base domain, then you will be able to pass your cookie.
Let's put more detail to it in case people want to know what would be the next step is, let's use the following example :-
You are developing on my.fancy.site.mydomain.com
Your Cloudfront CNAME alias is content.mydomain.com
Make sure you set your cloudfront signed cookies to .mydomain.com from your fancy app
From this point on, you are able to pass the cookie for the CF.
One quick way to test if your cookie is set appropriately, try to get your assets URL, and put the url in the browser directly. If the cookie set correctly, you will be able to access the file directly.
If you are using javascript to get the cdn assets, make sure in your JS code, you need to pass withCredentials option, or it won't work. For example, if you are using jQuery, you will need something like the following :-
$.ajax({
url: a_cross_domain_url,
xhrFields: {
withCredentials: true
}
});
And if the request is successful, you should get a response header from CloudFront with "Access-Control-blah-blah".
Hope it helps people if they search this answer.
I found a very similar issue. The CloudFront distribution was not sending the header information to S3. You can test this easily via:
curl -i -H "Origin: http://YOUR-SITE-URL" http://S3-or-CLOUDFRONT-URL | grep Access
If you have the same problem, you can see my solution here:
AWS S3 + CloudFront gives CORS errors when serving images from browser cache

AWS Cloudfront redirecting form post to origin

Hi I have a dynamic application that has a search form. I'm trying to use CloudFront with a load balancer. When you do a search the application creates some URL parameters and reloads the page. For some reason cloudfront is doing a 302 redirect back to the origin. Does anybody know how to fix this?
I have the following configuration.
It's clear that you're going to want to turn on Forward Query Strings. Without it, cloudfront will treat the following urls as the same:
http://www.example.com
http://www.example.com?q=search_term
http://www.example.com?q=search_term&option=true
It's however not clear to me that this would result in 302 to the original url (btw. origin means something very specific when dealing with cloudfront/other cdns - it's often short for origin server which is the source behind the cdn)
The 302 redirect is much more likely to your Viewer Protocol Policy, which you have set http requests to redirect to http. You should double check that your application isn't reloading the http version of the page.