web-dev-qa-db-fra.com

Angular 4.3 HttpClient: Réponse d'interception

Dans la documentation sur la nouvelle HttpClientModule incluse dans la nouvelle version de Angular 4.3, le mécanisme d’interception des requêtes est très bien expliqué. Il est également fait mention du mécanisme d'interception de la réponse, mais je ne trouve rien à ce sujet.

Quelqu'un at-il une idée de la façon d'intercepter une réponse afin de modifier le corps du message avant qu'il ne soit envoyé au service?

Merci.

50
olivier houssin

J'ai récemment créé un HttpInterceptor afin de résoudre les références cycliques dans certains JSON côté client, en remplaçant essentiellement tout objet par une propriété $ref par l'objet du JSON correspondant à $id. propriété. (Il s’agit du résultat obtenu si Json.Net est configuré avec PreserveReferencesHandling.Objects et ReferenceLoopHandling.Ignore).

Les réponses fournies ici m'ont aidé dans une certaine mesure, mais aucune d'elles n'a montré comment modifier le corps de la réponse, à l'instar des besoins du PO. Pour ce faire, il faut cloner l'événement et mettre à jour le corps, comme suit:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).map(event => {
        if (event instanceof HttpResponse && shouldBeIntercepted(event)) {
            event = event.clone({ body: resolveReferences(event.body) })
        }         
        return event;
    });
}

Tout événement qui ne devrait pas être modifié est simplement transmis au gestionnaire suivant.

38
sigbjornlo

Je suppose que vous pouvez utiliser do comme suggéré par @ federico-scamuzzi, ou vous pouvez utiliser map et catch comme suit:

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

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.info('req.headers =', req.headers, ';');
    return next.handle(req)
      .map((event: HttpEvent<any>) => {
        if (event instanceof HttpResponse && ~~(event.status / 100) > 3) {
          console.info('HttpResponse::event =', event, ';');
        } else console.info('event =', event, ';');
        return event;
      })
      .catch((err: any, caught) => {
        if (err instanceof HttpErrorResponse) {
          if (err.status === 403) {
            console.info('err.error =', err.error, ';');
          }
          return Observable.throw(err);
        }
      });
  }
}

EDIT: @LalitKushwah demandait de rediriger if(!loggedIn). J'utilise Route Guards , plus précisément:

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot
       } from '@angular/router';

import { Observable } from 'rxjs/Observable';

import { AuthService } from '../../api/auth/auth.service';
import { AlertsService } from '../alerts/alerts.service';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private router: Router,
              private alertsService: AlertsService) {}

  canActivate(next: ActivatedRouteSnapshot,
              state: RouterStateSnapshot
              ): Observable<boolean> | Promise<boolean> | boolean {
    if (AuthService.loggedIn()) return true;

    const url: string = state.url;

    this.alertsService.add(`Auth required to view ${url}`);
    this.router
      .navigate(['/auth'], { queryParams: { redirectUrl: url } })
      .then(() => {});
    return false;
  }
}

Ensuite, je peux simplement ajouter cela comme argument à mon itinéraire:

{
  path: 'dashboard', loadChildren:'app/dashboard/dashboard.module#DashboardModule',
  canActivate: [AuthGuard]
}
45
A T

Avec la version Angular 6, ils ont adapté RxJs 6.0 en raison de ce que la plupart des solutions ci-dessus ne fonctionneront pas dans cette version particulière de angular. C’est ainsi que vous modifiez correctement le contenu d’un observable.



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

@Injectable()
export class ResponseInterceptor implements HttpInterceptor {

    intercept(req: HttpRequest, next: HttpHandler): Observable<HttpEvent<any>> {

        return next.handle(req).pipe(tap((event: HttpEvent<any>) => {
            if (event instanceof HttpResponse) {
                event = event.clone({body: this.modifyBody(event.body)});
            }
            return event;
        }));

    }

    private modifyBody(body: any) {
        /*
        * write your logic to modify the body
        * */
    }
}

18

D'après ce que je peux comprendre (je n'ai fait que l'interception à la demande et l'injection d'auth token) .. vous pouvez attacher un .do () et tester si est une réponse .. like (comme le dit la doc):

import 'rxjs/add/operator/do';

export class TimingInterceptor implements HttpInterceptor {
  constructor(private auth: AuthService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const started = Date.now();
    return next
      .handle(req)
      .do(event => {
        if (event instanceof HttpResponse) { //<-- HERE
          const elapsed = Date.now() - started;
          console.log(event} ms.`);
        }
      });
  }

}
4
federico scamuzzi