42

I'm writing an Angular SPA app, that uses HttpClient to get values from my backend.

What is the easy way to tell it not to cache? The first time I ask it gets the value, then it refuses to make subsequent queries.

Thanks, Gerry

Gerry
  • 1,838
  • 5
  • 24
  • 32
  • Do you have control of the backend as well? – user184994 Nov 09 '18 at 19:51
  • can you include the code of these requests?, and the component template also, and what backend framework are you using if any? – Hussein Nov 09 '18 at 19:52
  • As far as I know you can't. I thought this was a function of the browser. I have heard of hacks like adding a random integer to the get so the browser doesn't match with a previous request. Otherwise I just post to my API. Caching get calls has caused me so much pain in the past. – Ryan E. Nov 09 '18 at 19:53
  • Looks like you can add some header attributes to your requests -> https://stackoverflow.com/questions/37755782/prevent-ie11-caching-get-call-in-angular-2 Looks like you can control this server side as well according to one of the commenters. – Ryan E. Nov 09 '18 at 19:54

4 Answers4

62

Using meta HTML tags, Disable browser caching:-

<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">

or,

Add headers in http request as:-

headers = new Headers({
        'Cache-Control':  'no-cache, no-store, must-revalidate, post- 
                            check=0, pre-check=0',
        'Pragma': 'no-cache',
        'Expires': '0'
    });
Mahi
  • 3,748
  • 4
  • 35
  • 70
29

HTTPInterceptors are great way to modify HTTP requests occurring in your application. It acts as an injectable service that can invoke when HttpRequest occurs.

HTTP Interceptor:

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

@Injectable()
export class CacheInterceptor implements HttpInterceptor {

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

    return next.handle(httpRequest);
  }
}

Using Interceptor:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

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

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true }
  ]
})
export class AppModule { }
Pramod Mali
  • 1,588
  • 1
  • 17
  • 29
  • 1
    I've noticed this is preventing my authorization bearer token to be set.Is there a way around this? – ronoc4 Apr 18 '20 at 08:37
  • @ronoc4 See https://angular.io/guide/http#setting-default-headers. You can set the auth token in the same interceptor or in a separate one. Example: const authReq = req.clone({ setHeaders: { Authorization: authToken } }); – Stevethemacguy Apr 27 '21 at 21:18
16

How about add salt to url:

const salt = (new Date()).getTime();
return this.httpClient.get(`${url}?${salt}`, { responseType: 'text' });

Same concept is used for static resource links in html (css or js) to trick the cache. Adding dynamic salt to url causes fresh loading of target each time because url is different every time, but in fact it is the same.

/static/some-file.css?{some-random-symbols}

I used date because it guarantee me unique number without using random and so on. We can just use incrementing integer for each call as well.

The code provided above worked fine for me in case when I couldn't change server configuration.

groont
  • 161
  • 1
  • 5
  • When possible, please make an effort to provide additional explanation instead of just code. Such answers tend to be more useful as they help members of the community and especially new developers better understand the reasoning of the solution, and can help prevent the need to address follow-up questions. – Rajan May 13 '20 at 10:59
  • 1
  • Nicely Works! Thanks – Zenwalker Aug 27 '23 at 14:20
6

As answered by Pramod, 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 { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'
  import { CacheInterceptor } from './cache-interceptor.service';

  // on providers
  providers: [{ provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true }]
John Wilfred
  • 157
  • 3
  • 6
  • 5
    this is the almost exactly the same answer as the answer from @Pramod – Coen Damen Dec 21 '19 at 09:48
  • This worked for me without overriding other headers. Also it was helpful that you noted in which files you recommend storing each instruction. – Nathan Clement Jun 26 '20 at 20:09
  • 2
    @CoenDamen No it isn't exactly the same. Pramod's answer uses new Header instantiation while this answer reuse the same header sent from req variable and add the no cache strategy using .set() method – Rafique Mohammed Aug 10 '22 at 10:57