角度4.3 HttpClient: 拦截响应

在 Angular 4.3的新版本中包含的关于新 HttpClientModule的文档中,很好地解释了拦截请求的机制。还提到了响应拦截器机制,但是我找不到有关它的任何信息。

有人知道如何拦截响应以便在正文消息发送到服务之前修改它吗?

谢谢。

85095 次浏览

据我所知(我只截取了请求和注入认证令牌)。.你可以附加一个。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.`);
}
});
}


}

我想你可以像@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);
}
});
}
}

编辑:@LalitKushwaa 正在询问关于重定向 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]
}

编辑: 从 Angular 15于2022年11月发布开始,你可以使用这个功能模式:

const route = {
path: 'admin',
canActivate: [() => inject(LoginService).isLoggedIn()]
};

我最近创建了一个 HttpInterceptor,以便在客户端解析某些 JSON 中的循环引用,本质上用具有匹配 $id属性的 JSON 中的对象替换具有 $ref属性的任何对象。(这是如果 Json。Net 配置了 PreserveReferencesHandling.ObjectsReferenceLoopHandling.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;
});
}

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

自从 Angular 6发布以来,RxJs 6.0改变了它的接口,因此您不能以同样的方式使用操作符(如 .map().tap()...)。
正因为如此,上述大多数解决方案都是过时的。
下面是如何使用 RxJs 6.0 + (使用 pipe)正确修改 Observer 的内容:


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


@Injectable()
export class ResponseInterceptor implements HttpInterceptor {


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


return next.handle(req).pipe(map((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
* */
}
}