2017-08-03 11 views
5

Próbuję zaimplementować buforowanie HttpRequest przy użyciuzgodnie z dokumentacją opisaną w punkcie 4.3. Ale dostaję błąd. Tu jest mój kodu:Nie można buforować przy użyciu obiektu HttpInterceptor w ustawieniu kątowym 4.3

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

tutaj CachingInterceptor pracuje jako kolektora na żądanie HTTP/odpowiedzi. I stworzyliśmy moduł A, która wygląda następująco:

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

Reklamowe jest również w dostawców [] na module. Jest to zgodne z dokumentacją pod kątem 4.3. Ale wciąż dostaję błąd jak:

błędu

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

mam 2 pytania:

  1. HttpCache jest klasą abstrakcyjną, to dlaczego jest on wstrzykiwany jak usługi?
  2. Mimo że wdrażam to zgodnie z oficjalną dokumentacją, to dlaczego otrzymuję ten błąd?
+0

Zaktualizowałem moją odpowiedź, aby naprawić błąd z wieloma żądaniami, sprawdź to. –

+0

dzięki @WillShaver – Shree

Odpowiedz

10

Jeśli szukasz super-prosty cache-wszystko-w-rzeczy realizacji:

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

Zauważ, że ten został zaktualizowany z oryginalnej metody. Oryginalna metoda intercept miała błąd - jeśli kilka próśb o identyczny adres URL próbowano przed pierwszym powrocie, wiele żądań nadal trafiało na serwer.

To rozwiązanie umożliwia przekazanie tylko jednego żądania na serwer.

Oryginalne rozwiązanie jest poniżej dla potomności. (Niezalecane.)

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

Dzięki. To takie proste.:) – Shree

+0

@ Shree, jeśli to jest to, co chciałeś, proszę oznaczyć go jako zaakceptowaną odpowiedź. Jeśli nie, proszę wyjaśnić, czego brakuje. –

2

Z tego co mogę powiedzieć, problem jest to, że jest to klasa abstrakcyjna

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

Trzeba by wdrożyć tę klasę i to metody w celu utworzenia wystąpienia go użyć w CachingInterceptor Klasa

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

Następnie użyj HttpCacheService w swojej klasie CachingInterceptor.

Ale dlaczego po prostu nie przechowywać żądań w jakiejś tablicy, jeśli próbujesz je zapisać w pamięci podręcznej? This article może być dobrym punktem wyjścia do tego, jak osiągnąć to, co próbujesz zrobić.

+0

Dzięki za rozwiązanie zadziałało w moim przypadku. :) –