Prevent IE11 caching GET call in Angular 2
JavascriptAngularTypescriptInternet Explorer-11Http CachingJavascript 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);
}
}