Использование OpenReplay с Angular
Важно помнить, что отслеживание должно выполняться вне хуков Zone.js Angular, чтобы избежать наложений и ненужных проверок.
Вот простой пример настройки трекера:
import { Injectable, NgZone } from '@angular/core';
import Tracker from '@openreplay/tracker';
import trackerAssist from '@openreplay/tracker-assist';
@Injectable({
providedIn: 'root',
})
export class OpenReplayService {
public tracker?: Tracker | null;
constructor(private zone: NgZone) {
this.zone.runOutsideAngular(() => {
this.tracker = new Tracker({
projectKey: 'abc123',
ingestPoint: 'https://someurl/',
});
this.tracker.use(
trackerAssist({
confirmText: `You have an incoming call from <Company> Support. Do you want to answer?`,
})
);
});
}
public async start() {
this.zone.runOutsideAngular(() => {
if (this.tracker) {
return this.tracker.start();
} else {
return {
sessionID: null,
sessionToken: null,
userUUID: null,
};
}
});
}
public setUserData(user: { id: string }): void {
this.zone.runOutsideAngular(() => {
if (this.tracker && user.id) {
this.tracker.setUserID(String(user.id));
}
});
}
}
Отслеживание HTTP-запросов
Section titled Отслеживание HTTP-запросовЕсли вы пытаетесь отслеживать запросы, отправляемые вашим приложением Angular, OpenReplay не предоставляет для этого плагин, как в случае с Fetch или Axios.
Тем не менее вы по-прежнему можете настроить его для отслеживания ваших запросов с нужной вам информацией с помощью HTTPInterceptor.
В этом руководстве я покажу вам, как создать HTTPInterceptor, способный записывать как запросы, так и ответы, отправляемые вашим HTTPClient.
Создание перехватчика
Section titled Создание перехватчикаПерехватчик — это особый тип объекта, который вы можете внедрить в код вашего приложения, чтобы перехватывать каждый запрос, отправляемый через HTTP-клиент Angular по умолчанию, и захватывать ответ.
Благодаря этой логике мы воспользуемся пользовательскими событиями OpenReplay, которые позволяют отправлять любое событие, которое вы хотите зафиксировать в рамках своей сессии, так что мы повторим то, что плагин Fetch или Axios делал бы для других конфигураций.
Код перехватчика выглядит следующим образом:
import { Injectable } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent,
HttpResponse,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { ReplaySessionService } from '../replay-session.service';
@Injectable({providedIn: 'root'})
export class HttpConfigInterceptor implements HttpInterceptor {
constructor(
private replaySessionService: ReplaySessionService,
) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
//This function will be called with the response a few lines below
const handleResponse = (request: HttpRequest<any>, response: HttpResponse<any>, event: string) => {
//we forward our data to the service, which will create the custom event and send it
this.replaySessionService.sendEventToReplaySession(event, { request, response })
}
return next.handle(request).pipe(
//filter out events that aren't http reponses
filter( (event: any) => event instanceof HttpResponse),
map( (resp: HttpResponse<any>) => { //for each response, call handleResponse
handleResponse(request, resp, `${request.url}`)
return resp
}),
map((event: HttpEvent<any>) => {
return event;
})
);
}
}
Сервис replay мы рассмотрим через секунду, а пока просто предположим, что он уже есть. Сохраните этот файл в папке app.
Затем отредактируйте файл app.module, добавив следующее внутри директивы @ngModule:
providers: [
{provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true}
]
Таким образом, файл app.module должен выглядеть примерно так:
import { NgModule } from '@angular/core';
/*
imports...
*/
import { HttpConfigInterceptor } from './interceptor/index';
@NgModule({
imports: [
/*...*/
],
providers: [
{provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true}
],
declarations: [
/*...*/
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
После того как с этим покончено, ваше приложение теперь знает, что нужно внедрять ваш перехватчик при каждом выполняемом HTTP-запросе.
Теперь давайте посмотрим на сам сервис session replay.
Создание SessionReplayService
Section titled Создание SessionReplayServiceСначала добавьте ваш новый сервис с помощью следующей команды:
$ ng generate service replay-session
Это создаст новый сервис Angular в корне вашего приложения под названием replay-session.service.ts
Содержимое этого файла должно выглядеть так:
import { Injectable } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpResponse,
} from '@angular/common/http';
import OpenReplay from '@openreplay/tracker'
type ReqRespType = {
request: HttpRequest<any>,
response: HttpResponse<any>
}
@Injectable({
providedIn: 'root'
})
export class ReplaySessionService {
tracker: OpenReplay|null = null
constructor() {
this.tracker = new OpenReplay({
projectKey: "<YOUR PROJECT KEY>",
})
//you can set up any other OR plugins here as well
this.tracker.start()
}
sendEventToReplaySession(event: string, params: ReqRespType): void {
const {request, response} = params
this.tracker?.event(event + "[request]", {
method: request.method,
url: request.url,
params: request.params
})
this.tracker?.event(event + "[response]", {
body: response.body,
status: response.status,
headers: response.headers
})
}
}
Конструктор класса, который, поскольку это сервис, как мы знаем, будет вызван только один раз, отвечает за создание экземпляра трекера и его запуск.
Затем в нашем методе sendEventToReplaySession мы используем метод event для отправки двух пользовательских событий.
Если вы вернётесь к классу перехватчика, то заметите, что «event» (первый параметр, который мы получаем в этом методе) на самом деле является URL, поэтому я добавляю к ним слова «[response]» и «[request]», чтобы определить, что и где записывается. Затем я формирую полезную нагрузку для каждого события, сохраняя только ту информацию, которую хочу сохранить.
Более того, вы можете даже взять этот код и очистить любое поле запроса или ответа, которое вы не хотите делать видимым внутри replay, перед вызовом метода event.
Вы можете ознакомиться с этим репозиторием, чтобы увидеть полный исходный код работающего приложения на основе Angular с трекером.
Есть вопросы?
Section titled Есть вопросы?Если у вас возникли какие-либо проблемы с настройкой трекера в вашем проекте Angular, свяжитесь с нами в нашем сообществе Slack и задайте вопросы нашим разработчикам напрямую!