Resolving Internet Explorer 11 caching issues with Angular and Ionic

November 18, 2018, 6:40 pm Categories:

Categories

Internet Explorer sucks - there's no two ways about it and, if you're like most developers, this probably isn't news to you.

What might be news though is how version 11 of that browser (supposedly an improvement on previous iterations of the product) caches HTTP GET requests after the first time they are executed.

I didn't realise this until I'd spent 2 days trying to figure out why the Angular components in my Ionic 3 application (which ran smoothly on that browser) weren't updating with new data after HTTP requests had been successfully fired off....until I discovered it was Internet Explorer 11 caching the HTTP requests.

Grr...

Fixing this issue is, thankfully, quite simple with Angular HttpInterceptors....

Intercept and resolve

Angular's HttpInterceptor class - as the name suggests - simply allows outgoing HTTP requests to be intercepted and transformed before passing the transformed request to the next interceptor in the request chain.

This is massively useful as, in my case, we can modify HTTP requests to implement no-cache headers.

As I needed to use such functionality on an application-wide basis it made sense that I provide this through its own dedicated service (which, in the context of my Ionic 4 applications would be located here - src/app/services/interceptor.service.ts).

This service would then implement Angular's HttpInterceptor functionality like so:

import { Injectable } from '@angular/core';
import { HttpHandler,
         HttpInterceptor,
         HttpEvent,
         HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';


/**
 * Manages interception and transformation of HTTP requests
 * @module InterceptorService
 * @implements HttpInterceptor
 */
@Injectable({
  providedIn: 'root'
})
export class InterceptorService implements HttpInterceptor {


  /**
   * @constructs
   */
  constructor() { }



  /**
   * Intercepts HTTP requests and adds no-cache headers to ensure that the URI resource returned is 
   * always the most current, up to date version
   * @public
   * @method intercept
   * @param {HttpRequest}   httpRequest   The Outgoing HTTP request to be intercepted    
   * @param {HttpHandler}   nextRequest   Transforms an HttpRequest object into a stream of HttpEvents
   * @returns {Observable<HttpEvent<any>>} 
   */
  intercept(httpRequest  : HttpRequest<any>, 
            nextRequest  : HttpHandler) : Observable<HttpEvent<any>> 
  {
      // Clones the outgoing HttpRequest object and injects the following 
      // no-cache related headers:
      // 1. Cache-Control         For HTTP 1.1. servers
      // 2. Pragma                Compatible with legacy HTTP 1.0 servers that do not support Cache-Control header
      // 3. Expires               Sets the expiry date as the unix epoch
      // 4. If-Modified-Since     Explicitly state that the request must comply with the given range
      const transformedRequest = httpRequest.clone({
        headers: httpRequest.headers.set('Cache-Control', 'no-cache')
          .set('Pragma', 'no-cache')
          .set('Expires', 'Thu, 01 Jan 1970 00:00:00 GMT')
          .set('If-Modified-Since', '0')
      });

      // Handles the transformed HttpRequest for the next interceptor in the chain 
      return nextRequest.handle(transformedRequest);
  }
}

In order for this service to work we'll also need to modify the application's root module (located within your application as the src/app/app.module.ts file) to import the InterceptorService and Angular's http modules as well as make use of the HTTP_INTERCEPTORS injection token like so:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { InAppBrowser } from '@ionic-native/in-app-browser/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { InterceptorService } from './services/interceptor.service';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, HttpClientModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    StatusBar,
    SplashScreen,
    InAppBrowser,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
    { provide: HTTP_INTERCEPTORS, useClass: InterceptorService, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

With those amendments to the project code now in place your application should be able to overcome any caching issues with Internet Explorer 11 (or in any other non-caching required contexts).

In summary

No matter how good Ionic/Angular is there will inevitably be situations where you experience your project's behaving in a strange/unexpected way - particularly where cross-browser usage is required.

With a recent Ionic 3 project that I was contracted to deliver this was thanks to Internet Explorer's caching HTTP GET requests. Hopefully my experiences and the solution I've outlined above will help anyone struggling with similar situations where Ionic/Angular may be being used.

If you've enjoyed what you've read and/or found this helpful please feel free to share your comments, thoughts and suggestions in the comments area below.

I explore different aspects of working with the Ionic 4 framework in my e-book featured below and if you're interested in learning more about further articles and e-books that I'm writing please sign up to my FREE mailing list.

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top