在 Angular 4.3的新版本中包含的关于新 HttpClientModule的文档中,很好地解释了拦截请求的机制。还提到了响应拦截器机制,但是我找不到有关它的任何信息。
HttpClientModule
有人知道如何拦截响应以便在正文消息发送到服务之前修改它吗?
谢谢。
据我所知(我只截取了请求和注入认证令牌)。.你可以附加一个。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,或者像这样使用 map和 catch:
do
map
catch
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)的问题。我使用的是 路线守卫,具体来说:
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.Objects和 ReferenceLoopHandling.Ignore)。
HttpInterceptor
$id
$ref
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; }); }
任何不应该修改的事件都会简单地传递给下一个处理程序。
自从 Angular 6发布以来,RxJs 6.0改变了它的接口,因此您不能以同样的方式使用操作符(如 .map()、 .tap()...)。 正因为如此,上述大多数解决方案都是过时的。 下面是如何使用 RxJs 6.0 + (使用 pipe)正确修改 Observer 的内容:
.map()
.tap()
pipe
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 * */ } }