Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid CORS with AWS Cloudfront, and clean SPA urls

I have a single-page app that lives in S3, fronted by Cloudfront. There's also a backend that the SPA talks to via AJAX requests. I'm trying to both:

  1. have clean URLs (a la https://keita.blog/2015/11/24/hosting-a-single-page-app-on-s3-with-proper-urls/), by asking cloudfront to rewrite 403 and 404 errors into 200s that produce the index page, and
  2. avoid CORS issues by adding a cloudfront behavior to proxy /api/* to the server (like https://stackoverflow.com/a/42883221/1586229).

Is it possible to accomplish both of these? The problem is that cloudfront will change even 403s and 404s that come from the api into 200 index.html responses.

If this can't be done, can you recommend another way to accomplish what I'm trying to do?

like image 899
bgschiller Avatar asked Sep 13 '18 02:09

bgschiller


1 Answers

This behavior can be accomplished with Lambda@Edge. Here's the plan:

Create a Lambda function that will be triggered on Origin Request (see diagram for where in the lifecycle that lands). Be sure to create it in us-east-1, as that's the only region where Lambdas to be used in Lambda@Edge can be defined.

Cloudfront possible locations for a Lambda@Edge function

The function has the following job: rewrite requests to paths like /login, /profile, /anything_other_than_assets into /index.html. For me, I was able to make the rule:

Something is an asset if it has an extension. Otherwise, it's a path

Hopefully, you can do the same, or similar. Here's how my function body looked (I used node 8)

const path = require('path')

exports.handler = (evt, ctx, cb) => {
    const {request} = evt.Records[0].cf

    if (!path.extname(request.uri)) {
        request.uri = '/index.html'
    }

    cb(null, request)
}

Make sure you "Publish a new version", and then copy the arn (found at the top of the page)

where to copy the ARN of your new lambda function

paste it in the "Lambda function associations" section of your S3 Origin's Behavior.

Where to paste the ARN of your lambda function

Because Lambda@Edge function associates are scoped to the Origin level, this redirect behavior won't affect your /api/* behavior.

Make sure to remove the custom error handlers. You won't need them anymore for your S3 behavior, and you don't want them for your api behavior.

like image 187
bgschiller Avatar answered Sep 18 '22 04:09

bgschiller