We use machine learning technology to do auto-translation. Click "English" on top navigation bar to check Chinese version.
Improve Single-Page Application (SPA) Performance with a Same Domain policy using Amazon CloudFront
In this post, we demonstrate how you can use a same domain policy with
Over the years, SPA frameworks such as ReactJs and AngularJs have become a popular method for developing and hosting websites while limiting resource usage on a web server. An SPA is a web application that interacts with the user/client by dynamically rewriting the current web page with new data from the web server via APIs. This dramatically improves the website’s performance and provides a more dynamic user experience.
A common method for SPA deployments has been leveraging the use of
Figure 1. Architecture of a typical SPA hosted in Amazon Web Services.
Before we dive into the performance challenges for this setup, let’s review some basic principles of CORS and preflight requests.
CORS and preflight requests
“CORS is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources”
CORS defines a method for client web applications that are loaded in one domain to interact with resources in a different domain. The mechanism that CORS uses for browsers to gain approval for resource utilization in another domain is via ‘preflight requests’. A CORS preflight request is a
In the context of an SPA, the API calls are often made to a different domain that hosts all of the API endpoints for backend applications. This pattern requires enabling CORS on the APIs. The previous example SPA deployed in Amazon Web Services requires enabling CORS on API Gateway because the API requests to backend applications are from a different origin than SPA.
One consequence of enabling CORS is a preflight request if the HTTP request isn’t a
One criteria for simple HTTP requests is that if a content type header is present, then it can only have values from text/plain
, multipart/form-data
or application/x-www-form-urlencoded
. Since REST API utilization is common, most application HTTP requests include the header content-type: application/json
, thus rendering the requests as non-simple.
In this setup, most HTTP requests will incur a preflight request before content can be served from backend applications. If the users accessing the website are in a different region than the API’s region, then the added latency for preflight requests can be significant and thereby degrade user experience due to poor performance.
The following diagram depicts the sequence of request and responses that occur for a non-simple HTTP request.
Figure 2. Sequence of requests and responses for CORS and non-simple http request.
One way to solve this issue is to make sure that the front-end and back-end component resources can be accessed from the same domain. This eliminates preflight requests and results in improved application performance. It can also be achieved by introducing a reverse proxy that can forward the requests to API Gateway. Instead of setting up proxy servers, we can leverage CloudFront’s multiple origin capability to solve this problem.
Using CloudFront to serve dynamic content from APIs
CloudFront is commonly used as a Content Delivery Network (CDN) and can also serve dynamic content from the application back end. Using CloudFront for this purpose eliminates the need for CORS preflight requests, since the entirety of the SPA is on the same origin. Note that the SPA also utilizes the CDN component by routing API requests to the closest point of presence using the Amazon Web Services backbone network. This allows for further performance improvement (reduced latency) and thereby user experience.
Figure 3. Architecture depicting the use of CloudFront to serve data from API Gateway.
Automate the deployment with Amazon Web Services Cloud Development Kit
The architecture depicted in the previous figure can be deployed automatically using
We prepared a
Prerequisites
For the deployment, you must have the following:
- An Amazon Web Services account. If you don’t have an Amazon Web Services account, then sign up
here . - Amazon Web Services CDK installed in your local environment.
- An S3 bucket for hosting SPA assets.
- CloudFront distribution.
- An
Amazon Web Services Lambda function. - An API Gateway REST API with a
proxy integration for the Lambda function.
Steps to deploy the package
1. Use your command-line shell to clone the
git clone https://github.com/aws-samples/cloudfront-spa-with-samedomain-multiorigin
2. Navigate to the repository’s root directory.
cd cloudfront-spa-with-samedomain-multiorigin
3. Run npm install
to install node package dependencies.
4. If this is your first time deploying stack with Amazon Web Services CDK in your Amazon Web Services account, then run the following command to bootstrap your Amazon Web Services environment.
cdk bootstrap
Note that bootstrapping launches resources into your Amazon Web Services environment that are required by Amazon Web Services CDK. These include an S3 bucket for storing files and Amazon Web Services Identity and Access Management (IAM) roles that grant permissions needed to run our deployment.
5. Deploy the Amazon Web Services CDK application.
cdk deploy
Let’s look at the configuration of the deployed resources. There are four main components deployed with the Amazon Web Services CDK along with the required roles and permissions.
The following screenshot shows how there are two origins configured on the CloudFront distribution. The first origin is configured to serve from the deployed REST API, and the second origin serves files from the S3 bucket hosting the SPA.
Figure 4. Figure showing multiple origins configured on CloudFront distribution.
Additionally, there are two behaviors configured on the distribution. This configuration determines which client requests should be served from Amazon S3 as opposed to API Gateway.
Figure 5. Figure showing additional behavior configured on CloudFront distribution.
In this deployment, we disabled caching on the behavior for the `/api/*`
path to make sure that API requests are always served from API gateway. However, we also enabled caching on the default behavior that serves SPA assets. Note that this isn’t a prerequisite. If your backend requires caching at CloudFront, then you can choose to enable it on the behavior. Furthermore, we set the Origin request policy to “AllViewerExceptHostHeader”. This policy is intended for use with Amazon API Gateway origins. This origin expects the Host header to contain the origin domain name, not the domain name of the CloudFront distribution. Forwarding the Host header from the viewer request to these origins can prevent them from working.
Figure 6. Figure showing configured properties on additional behavior.
For the API Gateway endpoint, CORS isn’t enabled since we’re relying on CloudFront as the origin for all requests. Note that this setup doesn’t restrict you from enabling CORS. If you have other consumers of the APIs that have a different origin domain, then you can still choose to enable CORS.
The repository includes a sample SPA that you can optionally deploy to the provisioned S3 bucket using below steps.
- Run the following commands to build the angular application.
cd sample-spa npm install && ng build
- Copy all build files generated under dist/sample-spa to the root of the provisioned S3 bucket.
- You can now access the website from the CloudFront distribution domain.
- Clean up Amazon Web Services resources by running the below command from project root directory
cdk destroy
This setup lets all client requests ending with /api/*
to be sent to API Gateway origin, while other requests are served from the S3 bucket hosting the SPA, which is the default behavior. This deployment lets you host SPA assets in the S3 bucket and essentially use CloudFront’s domain for accessing both the front end application and back end APIs from the client browser. In addition to the performance improvement from eliminating preflight requests, your workload also benefits from improved latency with CloudFront’s points of presence (POP’s).
However, there is a trade off to consider with this pattern. For example, a setup where all of the requests from the front end are fronted by a single CloudFront distribution, but the API gateway has other consumers not originating from CloudFront where you want to have different web application firewall rules. In this case, you need a separate web application firewall enabled for CloudFront and API gateway, which may have overlapping firewall rules. This would increase the cost depending on how many firewall rules are evaluated multiple times for the same requests.
Conclusion
In this post, we learned how to use
The mentioned AWS GenAI Services service names relating to generative AI are only available or previewed in the Global Regions. Amazon Web Services China promotes AWS GenAI Services relating to generative AI solely for China-to-global business purposes and/or advanced technology introduction.