- Newest
- Most votes
- Most comments
You can create a Lambda@Edge function that triggers on the "Origin Response" event. In the function, check if the response is a 404
and the request URI starts with /app
; if so, modify the response to return your SPA's index.html
with a 200
status code. Deploy this Lambda function to your CloudFront distribution, associating it with the cache behavior for your SPA.
As example of your Lambda@Edge:
exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; const response = event.Records[0].cf.response; if (response.status === '404' && request.uri.startsWith('/app')) { response.status = '200'; response.statusDescription = 'OK'; response.headers['content-type'] = [{ key: 'Content-Type', value: 'text/html' }]; response.body = 'Your SPA index.html content goes here'; } callback(null, response); };
Key Sources:
For anyone stumbling upon this, here is how I ended up solving it:
Since my SPA origin should always serve index.html regardless of the path, instead of intercepting the response at error-time, I simply change the URI for all requests to the path to /app/index.html
. That way, when CloudFront receives the path /app/page1
or /app/page2
, etc., they are all converted to /app/index.html
under the hood. I implemented this using a simple Lambda@Edge function, like this:
export const handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
request.uri = "/app/index.html"
return callback(null, request);
};
I then associated this function to both the /app
and /app/*
behavior in my CloudFront distribution.
My only lingering question is why a vanilla CloudFront function didn't work. I tried this:
function handler(event) {
var request = event.request;
var uri = request.uri;
if (uri.startsWith("/app")) {
request.uri = "/app/index.html"
}
return request
}
But it would give me 404 errors when I tried to use it...
Relevant content
- Accepted Answerasked 2 years ago
- AWS OFFICIALUpdated a year ago
- AWS OFFICIALUpdated 2 years ago
- AWS OFFICIALUpdated 9 months ago
- AWS OFFICIALUpdated 8 months ago
Thank you Osvaldo, this almost gets me there. The only part of this solution that I am stuck on is this line:
response.body = 'Your SPA index.html content goes here';
Does this imply I have to hardcode the content of index.html from the SPA bucket in the lambda function? I am wondering if there is any way to avoid this.
Sure, please update the
response.body
by fetching the object from your S3 bucket. Here's an example to guide you:Ended up solving it using a different approach, see below.