Unable to cache using HttpInterceptor in angular 4.3

I am trying to implement HttpRequest caching using HttpInterceptor as per angular 4.3 documentation. But I get an error message. Here is my code:

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

Here, the CachingInterceptor works as an interceptor for an HTTP request / response. And I created a module a that looks like this:

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

The token is also provided in the providers of the [] module. This is consistent with the angular 4.3 documentation. But still I get an error, for example:

Error

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

I have 2 questions:

  • HttpCache is an abstract class, why is it introduced as a service?
  • Despite the fact that I implement it in accordance with the official documentation, why am I getting this error?
+5
source share
2 answers

If you are looking for a super-simple caching implementation of all things:

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

Note that this has been updated from the original method. The initial intercept method had an error: if several attempts of the identical URL were made before the first return, several requests would still be sent to the server.

This solution allows you to send only one request to the server.

The original solution is below for posterity. (Not recommended.)

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

From what I can say, your problem is that it is an abstract class

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

You will need to implement this class and its methods in order to instantiate it for use in your CachingInterceptor class

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

Then use the HttpCacheService in your CachingInterceptor class.

But why not just store requests in some sort of array if you are trying to cache them? This article can be a good starting point on how to accomplish what you are trying to do.

+2
source

Source: https://habr.com/ru/post/1270529/


All Articles