web-dev-qa-db-ja.com

Angular 4.3 HttpClient:インターセプト応答

Angular 4.3の新しいバージョンに含まれる新しいHttpClientModuleに関するドキュメントでは、リクエストをインターセプトするメカニズムが非常によく説明されています。応答インターセプターメカニズムについても言及していますが、それについては何も見つかりません。

ボディメッセージをサービスに送信する前に変更するために、応答をインターセプトする方法についてだれかが考えていますか?

ありがとう。

50
olivier houssin

私は最近、クライアント側のいくつかのJSONの循環参照を解決するためにHttpInterceptorを作成し、本質的に$refプロパティを持つオブジェクトを、一致する$idを持つJSONのオブジェクトに置き換えましたプロパティ。 (これは、Json.NetがPreserveReferencesHandling.ObjectsおよびReferenceLoopHandling.Ignoreで構成されている場合に得られる出力です)。

ここでの回答は何らかの形で役立ちましたが、OPのニーズのように、応答の本文を変更する方法を示すものはありません。そのためには、次のように、イベントを複製して本体を更新する必要があります。

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

変更してはならないイベントは、単に次のハンドラーに渡されます。

38
sigbjornlo

@ federico-scamuzziが提案したようにdoを使用できるか、またはmapcatchを次のように使用できると思います。

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

編集:@LalitKushwahはif(!loggedIn)のリダイレクトについて尋ねていました。 ルートガード を使用します。具体的には:

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

次に、それを引数としてルートに追加するだけです。

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

Angular 6リリースでは、上記のソリューションのほとんどがこの特定のリリースの角度で動作しないため、RxJs 6.0に適合しました。これが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

私が理解できることから(私はリクエストのインターセプトを行い、認証トークンを挿入するだけです).. .do()を添付して、応答が..

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