Как выполнить кеширование http get запроса в angular 5? - PullRequest
2 голосов
/ 13 марта 2019
    import { Injectable } from '@angular/core';
    import { HttpClient, HttpErrorResponse } from '@angular/common/http';
    import { Observable } from 'rxjs';
    import { catchError } from 'rxjs/operators';

    @Injectable()
    export class ApiService {

      constructor(private http: HttpClient) { }

      // get API request
      public apiGetRequest(url: any): Observable<any> {
        return this.http.get(url)
          .pipe(
            catchError(this.handleError('apiGetRequest'))
          );
      }
    }

Я использую angular 5 с версией rxjs 5.5.6. Я пытаюсь кэшировать несколько запросов http http.

Ответы [ 5 ]

1 голос
/ 14 марта 2019

Вы можете создать внутреннее ключ / значение решение для хранения пар для кэширования запроса.Здесь я использую Map () для этого.

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

@Injectable()
export class CacheInterceptor implements HttpInterceptor {
  private cache = new Map<string, any>();

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

    const cachedResponse = this.cache.get(request.url);
    if (cachedResponse) {
      return of(cachedResponse);
    }

    return next.handle(request).pipe(
      tap(event => {
        if (event instanceof HttpResponse) {
          this.cache.set(request.url, event);
        }
      })
    );
  }
}

Теперь вам нужно позаботиться о недействительности кэша.всякий раз, когда данные изменяются, вам нужно сделать недействительными.

1 голос
/ 13 марта 2019

Это служба кэширования, которую я использую, она хранит данные в хранилище Redux, но ее легко поменять на любой нужный вам держатель данных.

@Injectable()
export class CacheManager {

  constructor(
    private store: NgRedux<IAppState>,
    private actions: GlobalActions) {
  }

  public get<T>(key: CacheKey, thisArg: any, dataRetriver: (...args: any[]) => T | Observable<T>, ...args: any[]): Observable<T> {
    if (this.isCached(key)) {
      return of(this.getFromCache<T>(key));
    }

    const data$: T | Observable<T> = dataRetriver.apply(thisArg, args);

    if (data$ instanceof Observable) {
      return data$.pipe(
        tap(result => this.addToCache(key, result))
      );
    }
    else {
      this.addToCache(key, data$);
      return of(data$);
    }
  }

  public clear(): void {
    this.store.dispatch(this.actions.clearCache());
  }

  private isCached(key: string): boolean {
    return this.cacheStorage[key] !== undefined;
  }

  private addToCache<T>(key: string, value: T): void {
    this.store.dispatch(this.actions.cache(key, value));
  }

  private getFromCache<T>(key: string): T {
    return <T>this.cacheStorage[key];
  }

  private get cacheStorage(): { [key: string]: any } {
    return this.store.getState().global.cache;
  }
}

и пример использования:

// call without cache:
this.service.loadPeriods(param1, param2)
  .pipe(...)
  .subscribe(...)

// call with cache ("periods" is a cache key):
this.cache.get("periods", this.service, this.service.loadPeriods, param1, param2)
  .pipe(...)
  .subscribe(...);
1 голос
/ 13 марта 2019

таким образом, без rxjs ?‍♂️, но вы можете проверить этот ответ

@Injectable()
export class CashingService {

  private __cach = {}
  isCashed(url: string) {
    return this.__cach[url];
  }

  getData(url: string) {
    return this.__cach[url]
  }

  setData(url) {
    return (data) => {
      if (data && (data instanceof Error) === false)
        this.__cach[url] = data
    };

  }

  reset() {
    this.__cach = {};
  }

}

Служба инъекционного чахания

@Injectable()
export class ApiService {

  constructor(private http: HttpClient , private _c:CachingService ) { }

  // get API request
  public apiGetRequest(url: any): Observable<any> {

    if (this._c.isCashed(url)){
     return of(this._c.getData(url));
    } else {
    return this.http.get(url)
      .pipe(
       tab(this._c.setData(url)),
       catchError(this.handleError('apiGetRequest'))
      );
    }

  }
}
1 голос
/ 13 марта 2019

Правильный способ сделать это будет так:

private varName$: Observable<T>;

private _apiGetRequest():Observable<T>{
 return this.http.get('endpoint');
}
public apiGetRequest():Observable<T>{
 if(!this.varName$){
  this.varName$ = this._apiGetRequest().pipe(shareReplay(1));
 }
 return this.varName$
}

Таким образом, частная наблюдаемая сохраняет последнее значение

1 голос
/ 13 марта 2019

Попробуйте что-то вроде этого:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';

@Injectable()
export class ApiService {

  private _someData: any;

  constructor(private http: HttpClient) { }

  public apiGetRequest(url: any): Observable<any> {

    /**
     * Returns cached data if exists.
     */
    if (this._someData) {
      return of(this._someData);
    }

    return this.http.get(url)
      .pipe(
        tap((someData: any) => {
          if (someData) {
            this._someData = someData;
          }
        }),
        catchError(this.handleError('apiGetRequest'))
      );
  }
}

В первый раз, когда мы получаем данные из API-интерфейса сервера, в следующий раз apiGetRequest() будет возвращать кэшированные данные.

...