无法在角度4.3中使用HttpInterceptor进行缓存

时间:2017-08-03 09:54:42

标签: angular

我正尝试按照角色4.3的文档使用HttpRequest实施HttpInterceptor缓存。但是我收到了错误。这是我的代码:

caching.interceptor.ts

import { HttpRequest, HttpResponse, HttpInterceptor, HttpHandler, HttpEvent } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';

import 'rxjs/add/operator/do';
import 'rxjs/add/observable/of';

abstract class HttpCache {
  abstract get(req: HttpRequest<any>): HttpResponse<any>|null;
  abstract put(req: HttpRequest<any>, resp: HttpResponse<any>): void;
}

@Injectable()
export class CachingInterceptor implements HttpInterceptor {
    constructor(private cache: HttpCache) {}

    intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>> {
        if(req.method !== 'GET'){
            return next.handle(req);
        }

        const cachedResponse = this.cache.get(req);

        if(cachedResponse){
            return Observable.of(cachedResponse);
        }

        return next.handle(req).do(event => {
            if(event instanceof HttpResponse){
                this.cache.put(req, event);
            }
        })
    }
}

此处CachingInterceptor用作http请求/响应的拦截器。我创建了模块a,看起来像:

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component/app.component';
import { HomePage } from './pages/home.page/home.page';
import { ProductsPage } from './pages/products.page/products.page';
import { AboutUsPage } from './pages/about-us.page/about-us.page';
import { UsersPage } from './pages/users.page/users.page';
import { DemoPage } from './pages/demo.page/demo.page';
import { appRouter } from './app.router/app.router';
import { CachingInterceptor } from './caching.interceptor/caching.interceptor';
import { AppService } from './app.service/app.service';

@NgModule({
    imports: [ BrowserModule, HttpClientModule, appRouter ],
    declarations: [ AppComponent, HomePage, ProductsPage, DemoPage, AboutUsPage, UsersPage ],
    providers: [ {
        provide: HTTP_INTERCEPTORS,
        useClass: CachingInterceptor,
        multi: true
    }, AppService ],
    bootstrap: [ AppComponent ]
})
export class AppModule {}

模块的providers []中也提供了令牌。这是根据角度4.3的文档。但我仍然得到如下错误:

错误

ERROR Error: Uncaught (in promise): Error: No provider for HttpCache!
Error: No provider for HttpCache!
    at injectionError (reflective_errors.ts:71)

我有两个问题:

  1. HttpCache是一个抽象类,那为什么它会像服务一样注入?
  2. 即使我按照官方文档执行它,为什么我会收到错误?

2 个答案:

答案 0 :(得分:15)

如果您正在寻找超级简单的缓存 - 所有这些实现:

import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";

@Injectable()
export class CacheInterceptor implements HttpInterceptor {
    private cache: { [name: string]: AsyncSubject<HttpEvent<any>> } = {};

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (request.method !== "GET") {
        return next.handle(request);
    }
    const cachedResponse = this.cache[request.urlWithParams] || null;
    if (cachedResponse) {
        return cachedResponse.delay(0);
    }
    const subject = this.cache[request.urlWithParams] = new AsyncSubject<HttpEvent<any>>();
    next.handle(request).do(event => {
        if (event instanceof HttpResponse) {
            subject.next(event);
            subject.complete();
        }
    }).subscribe(); // must subscribe to actually kick off request!
    return subject;
}

请注意,这已从原始方法更新。最初的intercept方法存在错误 - 如果在第一次返回之前尝试了多个相同网址的请求,则多个请求仍然会到达服务器。

此解决方案只允许将一个请求传递到服务器。

原始解决方案是针对子孙后代的。 (不推荐。)

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (request.method !== "GET") {
        return next.handle(request);
    }
    const cachedResponse = this.cache[request.urlWithParams] || null;
    if (cachedResponse) {
        return Observable.of(cachedResponse);
    }

    return next.handle(request).do(event => {
        if (event instanceof HttpResponse) {
            this.cache[request.urlWithParams] = event;
        }
    });
}

答案 1 :(得分:2)

据我所知,你的问题是这是一个抽象类

abstract class HttpCache {
    abstract get(req: HttpRequest<any>): HttpResponse<any>|null;
    abstract put(req: HttpRequest<any>, resp: HttpResponse<any>): void;
}

您需要实现此类及其方法,以便创建要在CachingInterceptor类中使用的实例

export class HttpCacheService implements HttpCache {
    get(req: HttpRequest<any>): HttpResponse<any>|null {
        // Some logic
    }
    put(req: HttpRequest<any>, resp: HttpResponse<any>): void {
       //Some logic
    }
}

然后在HttpCacheService课程中使用CachingInterceptor

但是,如果您尝试缓存请求,为什么不将请求存储在某种数组中呢? This article可能是如何完成你想要做的事情的一个很好的起点。