Prevent IE11 caching GET call in Angular 2

JavascriptAngularTypescriptInternet Explorer-11Http Caching

Javascript Problem Overview


I have a rest endpoint that returns a list on a GET call. I also have a POST endpoint to add new items and a DELETE to remove them. This works in Firefox and Chrome, and the POST and DELETE work in IE11. However, the GET in IE11 only works on initial load of the page. Refreshing returns cached data. I have seen post about this behavior in Angular 1 but nothing for Angular 2(release candidate 1).

Javascript Solutions


Solution 1 - Javascript

For Angular 2 and newer, the easiest way to add no-cache headers by overriding RequestOptions:

import { Injectable } from '@angular/core';
import { BaseRequestOptions, Headers } from '@angular/http';

@Injectable()
export class CustomRequestOptions extends BaseRequestOptions {
    headers = new Headers({
        'Cache-Control': 'no-cache',
        'Pragma': 'no-cache',
        'Expires': 'Sat, 01 Jan 2000 00:00:00 GMT'
    });
}

Module:

@NgModule({
    ...
    providers: [
        ...
        { provide: RequestOptions, useClass: CustomRequestOptions }
    ]
})

Solution 2 - Javascript

Today, I also had this problem, (damn IE). In my project, I use httpclient, that hasn't BaseRequestOptions. We should use Http_Interceptor to resolve it!

import { HttpHandler,
    HttpProgressEvent,
    HttpInterceptor,
    HttpSentEvent,
    HttpHeaderResponse,
    HttpUserEvent,
    HttpRequest,
    HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

export class CustomHttpInterceptorService implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler):
      Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
      const nextReq = req.clone({
        headers: req.headers.set('Cache-Control', 'no-cache')
          .set('Pragma', 'no-cache')
          .set('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT')
          .set('If-Modified-Since', '0')
      });

      return next.handle(nextReq);
  }
}

Module provide

@NgModule({
    ...
    providers: [
        ...
        { provide: HTTP_INTERCEPTORS, useClass: CustomHttpInterceptorService, multi: true }
    ]
})

Solution 3 - Javascript

Forward the stackoverflow response https://stackoverflow.com/questions/16098430/angular-ie-caching-issue-for-http, you should add the headers 'Pragma', 'no-cache', 'If-Modified-Since' to each 'GET' request.

The interceptor's scenario is not supported to angular 2 anymore. So you should extend the http as it is described here https://stackoverflow.com/questions/35498456/what-is-httpinterceptor-equivalent-in-angular2.

Angular 4.3 now includes the HttpClient service, which supports interceptors.

Solution 4 - Javascript

Edit: See comment below - this is not necessary (in the vast majority of cases).

Expanding on Jimmy Ho's answer above, I only want to prevent caching of my API calls, and not other static content which will benefit from being cached. All of my API calls are to URLs that contain "/api/", so I amended Jimmy Ho's code with a check that only adds the cache headers if the requested URL contains "/api/":

import { HttpHandler,
    HttpProgressEvent,
    HttpInterceptor,
    HttpSentEvent,
    HttpHeaderResponse,
    HttpUserEvent,
    HttpRequest,
    HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

export class CustomHttpInterceptorService implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler):
    Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
    // Only turn off caching for API calls to the server.
    if (req.url.indexOf('/api/') >= 0) {
        const nextReq = req.clone({
            headers: req.headers.set('Cache-Control', 'no-cache')
                .set('Pragma', 'no-cache')
                .set('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT')
                .set('If-Modified-Since', '0')
        });

        return next.handle(nextReq);
    } else {
        // Pass the request through unchanged.
        return next.handle(req);
    }
}

}

Solution 5 - Javascript

As answered above, you can use http request interceptor to modify or set a new header on the request. Below is a much simpler way of setting headers on http request interceptor for Later angular versions(Angular 4+). This approach would only set or update a certain request header. This is to avoid removing or overriding some important headers like the authorization header.

// cache-interceptor.service.ts
import { Injectable } from '@angular/core';
import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
} from '@angular/common/http';

@Injectable()
export class CacheInterceptor implements HttpInterceptor {

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    const httpRequest = req.clone({
      headers: req.headers
        .set('Cache-Control', 'no-cache')
        .set('Pragma', 'no-cache')
        .set('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT')
    })

    return next.handle(httpRequest)
  }
}

// app.module.ts

  import { HTTP_INTERCEPTORS } from '@angular/common/http'
  import { CacheInterceptor } from './cache-interceptor.service';

  // on providers
  providers: [{ provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true }]

Solution 6 - Javascript

Disable browser caching with meta HTML tags:-

<meta http-equiv="cache-control" content="no-cache, must-revalidate, post-check=0, pre-check=0">
<meta http-equiv="expires" content="0">
<meta http-equiv="pragma" content="no-cache">

Solution 7 - Javascript

A little late, but I ran into the same problem. For Angular 4.X I wrote a custom Http class to append a random number to the end to prevent caching by IE. It is based on the 2nd link by dimeros (https://stackoverflow.com/questions/35498456/what-is-httpinterceptor-equivalent-in-angular2). Warning: not guaranteed to be 100% bug free.

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Http, Response, XHRBackend, RequestOptions, RequestOptionsArgs, 
URLSearchParams } from '@angular/http';

@Injectable()
export class NoCacheHttp extends Http {
    constructor(backend: XHRBackend, options: RequestOptions) {
        super(backend, options);
    }

    get(url: string, options?: RequestOptionsArgs): Observable<Response> {
        //make options object if none.
        if (!options) {
            options = { params: new URLSearchParams() };
        }
        //for each possible params type, append a random number to query to force no browser caching.
        //if string
        if (typeof options.params === 'string') {
            let params = new URLSearchParams(options.params);
            params.set("k", new Date().getTime().toString());
            options.params = params;

        //if URLSearchParams
        } else if (options.params instanceof URLSearchParams) {
            let params = <URLSearchParams>options.params;
            params.set("k", new Date().getTime().toString());

        //if plain object.
        } else {
            let params = options.params;
            params["k"] = new Date().getTime().toString();
        }
        return super.get(url, options);
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncmaynardView Question on Stackoverflow
Solution 1 - JavascriptVitaliy UlantikovView Answer on Stackoverflow
Solution 2 - JavascriptJimmy HoView Answer on Stackoverflow
Solution 3 - JavascriptdimerosView Answer on Stackoverflow
Solution 4 - JavascriptAndrWeisRView Answer on Stackoverflow
Solution 5 - JavascriptJohn WilfredView Answer on Stackoverflow
Solution 6 - JavascriptMahiView Answer on Stackoverflow
Solution 7 - JavascriptChris MooreView Answer on Stackoverflow