Spring and Angular applications on Azure (7 Part Series)
This blog post is part of a series on "deploying a Spring Boot and Angular application on Azure", here is the full list of posts:
- Creating a Spring Boot and Angular application for Azure (1/7)
- Creating and configuring Azure Web App and MySQL to host a Spring Boot application (2/7)
- Using Azure Pipelines to build, test and deploy a Spring Boot and Angular application (3/7)
- Using Azure Application Insights with Spring Boot (4/7)
- Using Azure Application Insights with Angular (5/7)
- Configuring Azure CDN to boost Angular performance (6/7)
- Configuring Azure Redis Cache to boost Sping Boot performance (7/7)
Links will be updated after each time a post is published.
Our current Angular application works really well, in fact its production build even gets a perfect "100" score when testing it with the Chrome audit tools. The JHipster team has been hard at work to give you the best possible application, but we can still make it better!
As we have generated everything into the same project, all the client-side code is served by Spring Boot. This is one of the critism we often hear about "full stack" projects, typically generated by JHipster, by people who didn't look closely at how this is supposed to be hosted.
First of all, this works totally fine for small projects, and is also more cost-efficient as there is no other associated cost.
Secondly, this can be improved by adding HTTP/2 support: it is disabled by default in JHipster, but there is a
jhipster.http.version property that can be set to use HTTP/2. This is a JHipster-only solution, so if you're using Spring Boot directly you'll have a bit of manual setup to do.
And last but not least, the best solution here is to use a Content Delivery Network (CDN), as:
- It will provide HTTP/2 support out-of-the-box
- It will localize assets closer to your users, resulting in better performance for them
We are going to use Azure CDN in this post, as it is fully integrated with Azure Web App, and very easy to use.
In terms of pricing, it's one of the less expensive on the market, and it costs less than $30 a month. Once again, if you are budget-conscious, don't use a CDN from the start: a "normal" Spring Boot + Angular application (like the ones created by JHipster) work really well out of the box. What is important is being able to scale later, and add a CDN when needed.
A CDN is going to cache all assets: this means that after a few requests to your servers, all requests will be served directly from the CDN, and will benefit from it. This means your application needs to be specifially coded in order to work well with a cache:
- Statics assets should have a hash in their name, so when a new version is released, the client browsers will fetch the new content.
- Correct HTTP headers must be sent from the server, so only the right content is cached.
- When doing HTTP calls to our Spring Boot back-end, requests should not go through the CDN.
Those three conditions are usually met with Angular applications, as those best practices are now well-known in the community. Of course, JHipster has followed those closely, so when you do a "production" build with JHipster:
- All assets will be minified, and will have a specific hash in their name.
- Spring Boot will send the correct HTTP headers.
- There is a parameter called
SERVER_API_URLin the Webpack build, to point to a specific API server.
As our content will not be served by the same server as our data, it should have a CORS (Cross-origin resource sharing) issue. This means that, by default, your API server will not answer requests coming from another domain: this is good for your API server (otherwise other people might use it), but most importantly for your users (as this opens the door to many attacks).
With Spring Boot, you have this protection by default. JHipster provides an easy-to-use configuration mechanism on top of it, but this just simplifies what Spring Boot provides.
In production, you should only allow your Angular application in the
allowed-origins parameter below - we are using
*, and thus accepting requests from anywhere, here as it's easier for tests:
jhipster: cors: allowed-origins: '*' allowed-methods: '*' allowed-headers: '*' exposed-headers: 'Authorization,Link,X-Total-Count' allow-credentials: true max-age: 1800
In your Azure Web App, select "Networking" and then "Azure CDN".
You can then create a new CDN endpoint, that will run on top of your existing Azure Web App. Of course, you should also configure your DNS server to point to that CDN, so your users will use your own domain name here.
That's all there is to do, you can now test that everything works fine:
- Using your browser, you can check that you are now using HTTP/2 to access your web application. Doing a Chrome audit should also show that you now respect this best practice.
- If you are using JHipster, you can access the "Metrics" screen, that allows you to monitor the number of HTTP requests sent to your server. You can do some "force reload" of the application, using both the CDN and the Web application directly: when using the CDN, you should have less HTTP requests coming to your application.
The changes done in our application for this blog post are all available in this commit.