如何在Angular 6中使用HttpClient的get方法禁用缓存

44

我正在编写一个使用 HttpClient 从后端获取值的 Angular SPA 应用程序。

如何简单地告诉它不要缓存?第一次请求时可以获取到值,但之后就拒绝了进行进一步的查询。

谢谢, Gerry


你也掌控后端吗? - user184994
你能否包含这些请求的代码?还有组件模板,如果有的话,你使用的后端框架是什么? - Hussein
据我所知,你不能这样做。我认为这是浏览器的一个功能。我听说过一些黑科技,例如将随机整数添加到Get中,以便浏览器不会与之前的请求匹配。否则,我就会向我的API提交。在过去,缓存Get调用给我带来了很多痛苦。 - Ryan E.
看起来你可以向请求添加一些头属性 -> https://dev59.com/PloU5IYBdhLWcg3wK0pX根据其中一个评论者的说法,看起来你也可以在服务器端控制这个。 - Ryan E.
5个回答

63

使用meta HTML标签,禁用浏览器缓存:

<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">
或者,在HTTP请求中添加标题:
headers = new Headers({
        'Cache-Control':  'no-cache, no-store, must-revalidate, post- 
                            check=0, pre-check=0',
        'Pragma': 'no-cache',
        'Expires': '0'
    });

1
实际上,我添加了一个CustomHttpInterceptor服务来处理我所有的http请求。 - Gerry
1
是的,在每个 HTTP 请求的拦截器中添加它是一个好主意。 - Mahi

29

HTTP拦截器是修改应用程序中发生的HTTP请求的好方法。它作为可注入服务而运行,可以在发生HttpRequest时调用。

HTTP拦截器:

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);
  }
}

使用拦截器:

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 { }

1
我注意到这会阻止我的授权令牌被设置。有没有解决办法? - ronoc4
@ronoc4 请参考 https://angular.io/guide/http#setting-default-headers。您可以在同一个拦截器或单独的拦截器中设置身份验证令牌。例如:const authReq = req.clone({ setHeaders: { Authorization: authToken } }); - Stevethemacguy

18

在url中添加盐如何?

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

在HTML中,静态资源链接(如CSS或JS)也会使用相同的概念来欺骗缓存。通过向URL添加动态salt,每次目标都会重新加载,因为URL每次都不同,但实际上是相同的。

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

我使用日期作为唯一数字的保证,而无需使用随机等方法。我们也可以为每个调用使用递增整数。

在我无法更改服务器配置的情况下,上述代码对我有效。


尽可能地,请努力提供额外的解释,而不仅仅是代码。这样的答案往往更有用,因为它们帮助社区成员,特别是新开发人员更好地理解解决方案的原因,并可以帮助防止需要回答后续问题的需要。 - Rajan
1
这是完美的。 - Pablo Sanchez Manzano
好的,非常有效!谢谢。 - Zenwalker

7

如Pramod所述,您可以使用http请求拦截器来修改或设置请求中的新标头。 对于较新版本的Angular(Angular 4+),以下是一种更简单的设置http请求拦截器标头的方法。该方法仅设置或更新某个请求标头。这样可以避免删除或覆盖一些重要的标头,例如授权标头。

// 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 }]

5
这几乎是与@Pramod的回答完全相同的答案。 - Coen Damen
这对我有用,而且没有覆盖其他标头。另外,你指出在哪些文件中建议存储每个指令也很有帮助。 - Nathan Clement
2
@CoenDamen 不完全相同。Pramod的答案使用新的Header实例化,而这个答案重用了从req变量发送的相同header,并使用.set()方法添加了无缓存策略。 - Rafique Mohammed

2
您还可以为每个请求的URL附加一个唯一的查询参数。这样可以使每个请求在浏览器中呈现出不同的样子,防止它使用缓存的响应。
const uniqueParam = new Date().getTime();
const url = `your-api-endpoint?cacheBuster=${uniqueParam}`;
this.http.get(url).subscribe(data => {
  // Handle the response data
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接