Angular 4.3 HttpClient: перехват ответа
В документации о новом HttpClientModule
включенном в новую версию Angular 4.3, механизм перехвата запросов объясняется очень хорошо. Также есть упоминание о механизме перехвата ответа, но я ничего не могу найти по этому поводу.
У кого-нибудь есть идеи о том, как перехватить ответ, чтобы изменить тело сообщения перед его отправкой в службу?
Благодарю.
Ответы
Ответ 1
Недавно я создал HttpInterceptor
для разрешения циклических ссылок в некоторых JSON на стороне клиента, по существу заменяя любой объект со свойством $ref
на объект в JSON, который имеет соответствующее свойство $id
. (Это вывод, который вы получите, если 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;
});
}
Любое событие, которое не должно быть изменено, просто передается следующему обработчику.
Ответ 2
Я полагаю, что вы можете использовать do
как предложено @federico-scamuzzi, или вы можете использовать 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);
}
});
}
}
РЕДАКТИРОВАТЬ: @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;
}
}
Тогда я могу просто добавить это в качестве аргумента к моему маршруту:
{
path: 'dashboard', loadChildren:'app/dashboard/dashboard.module#DashboardModule',
canActivate: [AuthGuard]
}
Ответ 3
С выпуском 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
* */
}
}
Ответ 4
Из того, что я могу понять (я только сделал перехват запроса и ввел токен аутентификации).. вы можете прикрепить .do() и проверить, является ли ответ. like (как говорит 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.`);
}
});
}
}
Ответ 5
Ниже приведена короткая статья с примерами как для перехватчиков запросов, так и для ответа: Вкус из нового клиента HTTP Angular