Javascript Angular 4.3 HttpClient:拦截响应

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45566944/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 03:06:28  来源:igfitidea点击:

Angular 4.3 HttpClient : Intercept response

javascriptangularhttpinterceptor

提问by olivier houssin

In the documentation about the new HttpClientModuleincluded in the new version of Angular 4.3, the mechanism to intercept requests is explained very well. There is also mention of the response interceptor mechanism however I cannot find anything about it.

HttpClientModuleAngular 4.3新版本所包含的新内容的文档中,对拦截请求的机制进行了很​​好的解释。还提到了响应拦截器机制,但是我找不到任何关于它的信息。

Does anyone have an idea about how to intercept a response in order to modify the body message before it is sent to the service?

有没有人知道如何拦截响应以便在将正文消息发送到服务之前对其进行修改?

Thanks.

谢谢。

采纳答案by sigbjornlo

I recently made an HttpInterceptorin order to resolve cyclical references in some JSON on the client side, essentially replacing any object with a $refproperty with the object in the JSON that has a matching $idproperty. (This is the output you get if Json.Net is configured with PreserveReferencesHandling.Objectsand ReferenceLoopHandling.Ignore).

我最近做了一个HttpInterceptor为了在客户端解析某些 JSON 中的循环引用,基本上用$ref具有匹配$id属性的 JSON 中的对象替换具有属性的任何对象。(如果 Json.Net 配置了PreserveReferencesHandling.Objects和 ,则这是您获得的输出ReferenceLoopHandling.Ignore)。

The answers here helped me some of way, but none of them show how to modify the body of the response, like the OP needs. In order to do so, one needs to clone the event and update the body, like so:

这里的答案在某种程度上帮助了我,但没有一个显示如何修改响应的主体,就像 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;
    });
}

Any event that should not be modified is simply passed through to the next handler.

任何不应修改的事件都会简单地传递给下一个处理程序。

回答by A T

I suppose you can use doas @federico-scamuzzi suggested, or you can use mapand catchlike so:

我想你可以使用do如@费德里科- scamuzzi建议,或者您可以使用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);
        }
      });
  }
}


EDIT: @LalitKushwah was asking about redirecting if(!loggedIn). I use Route Guards, specifically:

编辑:@LalitKushwah 正在询问重定向if(!loggedIn)。我使用Route Guards,特别是:

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

Then I can simply add that as an argument to my route:

然后我可以简单地将它作为参数添加到我的路线中:

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

回答by imal hasaranga perera

With Angular 6 release they have adapted RxJs 6.0 because of that most of the above solutions will not work in this particular release of angular, this is how you correctly modify content of an Observable

随着 Angular 6 的发布,他们已经适应了 RxJs 6.0,因为上述大多数解决方案在这个特定的 angular 版本中都不起作用,这就是你如何正确修改 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
        * */
    }
}


回答by federico scamuzzi

From what i can understand (I've only done the intercept for request and inject auth token) .. you can attach a .do() and test if is a reponse .. like (as doc says):

据我所知(我只完成了请求的拦截并注入了身份验证令牌)..你可以附加一个 .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.`);
        }
      });
  }

}