Caching and Cache-Busting in AngularJS with HTTP interceptors
#
Loading On-Demand and CachingI've written before about my own needs for caching and cache-busting when using RequireJS. Long story short, when I'm loading static resources (scripts / views etc) on demand from the server I want to do a little URL fiddling along the way. I want to do that to cater for these 2 scenarios:
- In Development - I want my URLs for static resources to have a unique querystring with each request to ensure that resources are loaded afresh each time. (eg so a GET request URL might look like this: "/app/layout/sidebar.html?v=IAmRandomYesRandomRandomIsWhatIAm58965782")
- In Production - I want my URLs for static resources to have a querystring with that is driven by the application version number. This means that static resources can potentially be cached with a given querystring - subsequent requests should result in a 304 status code (indicating “Not Modified”) and local cache should be used. But when a new version of the app is rolled out and the app version is incremented then the querystring will change and resources will be loaded anew. (eg a GET request URL might look like this: "/app/layout/sidebar.html?v=1.0.5389.16180")
#
Loading Views in AngularJS Using this ApproachI have exactly the same use cases when I'm using AngularJS for views. Out of the box with AngularJS 1.x views are loaded lazily (unlike controllers, services etc). For that reason I want to use the same approach I've outlined above to load my views. Also, I want to prepend my URLs with the root of my application - this allows me to cater for my app being deployed in a virtual folder.
It turns out that's pretty easy thanks to HTTP interceptors. They allow you to step into the pipeline and access and modify requests and responses made by your application. When AngularJS loads a view it's the HTTP service doing the heavy lifting. So to deal with my own use case, I just need to add in an HTTP interceptor that amends the get request. This is handled in the example that follows in the configureHttpProvider
function: (The example that follows is TypeScript - though if you just chopped out the interface and the type declarations you'd find this is pretty much idiomatic JavaScript)
This interceptor steps in and amends each ajax request when all the following conditions hold true:
- It's a GET request.
- It's requesting a file that ends ".html" - a template basically.
- The template cache does not already contain the template. I left this out at first and got bitten when I found that the contents of the template cache were being ignored for pre-primed templates. Ugly.
#
Interesting technique.... How do I apply it?Isn't it always much more helpful when you can see an example of code in the context of which it is actually used? Course it is! If you want that then take a look at app.ts
on GitHub. And if you'd like the naked JavaScript well that's there too.