【问题标题】:Prevent IE11 caching GET call in Angular 2防止 IE11 在 Angular 2 中缓存 GET 调用
【发布时间】:2016-10-11 20:48:16
【问题描述】:

我有一个休息端点,它在 GET 调用中返回一个列表。我还有一个 POST 端点来添加新项目和一个 DELETE 来删除它们。这在 Firefox 和 Chrome 中有效,而 POST 和 DELETE 在 IE11 中有效。但是,IE11 中的 GET 仅适用于页面的初始加载。刷新返回缓存数据。我在 Angular 1 中看到过关于这种行为的帖子,但对于 Angular 2(候选版本 1)却没有。

【问题讨论】:

  • 如果你的 GET api 没有指定 Any Cache Control header -> 如果状态为 200 OK 则表示响应是可缓存的。
  • 另请参阅stackoverflow.com/questions/36500804/… 以了解客户端解决方法。
  • @Loc 我添加了 Cache-Control 值 no-store 和 no-cache ,但在 IE 中仍然得到相同的结果。
  • 看起来我需要指定更多缓存头,我有 Cache-Control: not-store, no-cache 需要添加 Pragma: no-cache Expires: 0

标签: javascript angular typescript internet-explorer-11 http-caching


【解决方案1】:

如上所述,您可以使用 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 { HTTP_INTERCEPTORS } from '@angular/common/http'
  import { CacheInterceptor } from './cache-interceptor.service';

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

【讨论】:

    【解决方案2】:

    编辑:请参阅下面的评论 - 这不是必需的(在绝大多数情况下)。

    扩展 Jimmy Ho 上面的回答,我只想防止缓存我的 API 调用,而不是其他将从缓存中受益的静态内容。我所有的 API 调用都是针对包含“/api/”的 URL,所以我修改了 Jimmy Ho 的代码,只在请求的 URL 包含“/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);
        }
    }
    

    }

    【讨论】:

    • HttpInterceptor 仅影响通过 Angular 的请求(因此通常是 HttpClient 在您的 Angular 服务中),这些请求在 99% 的时间都是 API 调用。所以我不认为这个额外的检查是必要的。除非您出于某种原因在服务层中请求静态内容,否则不会。
    • @LambdaCruiser,是的,你说的很对。这并不是真正需要的。我会把这个留在这里,以防万一有人落入同样的陷阱。
    【解决方案3】:

    对于 Angular 2 和更新版本,通过覆盖 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'
        });
    }
    

    模块:

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

    【讨论】:

    • 这是一个很好的解决方案,可以让来自角度请求的所有请求都没有缓存,但是我不希望所有请求都出现这种行为,因为某些请求可以被很好地缓存。我设置了适当的标头服务器端。无论如何,我宁愿服务器具有缓存智能。我的问题可能措辞不佳。
    • @cmaynard 我在寻找如何为 Andular 设置全局缓存时遇到了你的问题,所以从谷歌的角度来看,你的措辞非常适合人们搜索的内容:)
    • 这个解决方案对我不起作用,我不得不使用docs.netapp.com/sgws-110/…手动禁用缓存
    • 是的,谢谢。 IE11 的又一次刺激!!
    【解决方案4】:

    使用元 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">
    

    【讨论】:

      【解决方案5】:

      今天我也遇到了这个问题,(该死的IE)。 在我的项目中,我使用httpclient,而没有BaseRequestOptions。 我们应该使用Http_Interceptor来解决它!

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

      模块提供

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

      【讨论】:

      • 谢谢,这是 Angular 5 的正确答案。但是,由于我在原始问题中指定了 Angular 2,我将把该答案标记为正确,请投赞成票!
      • 如果您使用 CORS,您可能需要将所有标头(Cache-Control、Pragma 等)添加到服务器端的 Access-Control-Request-Headers。否则你会遇到 CORS 问题。这意味着您的请求将失败。
      【解决方案6】:

      转发 stackoverflow 响应 Angular IE Caching issue for $http,您应该将标头“Pragma”、“no-cache”、“If-Modified-Since”添加到每个“GET”请求。

      angular 2 不再支持拦截器的场景。因此,您应该按照此处What is httpinterceptor equivalent in angular2? 的描述扩展http。

      Angular 4.3 现在包含 HttpClient 服务,它支持拦截器。

      【讨论】:

        【解决方案7】:

        有点晚了,但我遇到了同样的问题。对于 Angular 4.X,我编写了一个自定义 Http 类以在末尾附加一个随机数以防止 IE 缓存。它基于 dimeros (What is httpinterceptor equivalent in angular2?) 的第二个链接。 警告:不保证 100% 没有错误。

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

        【讨论】:

        • 我过去曾使用该技术来“愚弄”缓存。我认为它很有用,但通常最好设置适当的标题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-04-11
        • 1970-01-01
        • 1970-01-01
        • 2017-01-31
        • 2012-03-31
        • 2011-03-26
        • 2016-03-31
        相关资源
        最近更新 更多