Я пытаюсь создать приложение в реальном времени, используя Angular 7 и Loopback SSE, как , описанное здесь , но я сталкиваюсь с двумя основными проблемами:
1) Я не смог установить аутентифицированное соединение .Обычно я делаю все http-запросы с токеном доступа в заголовке, но EventSource
не имеет API для отправки HTTP-заголовков на сервер.Поэтому я пытаюсь добавить параметры "access_token" в URL и пытаюсь также использовать пакет ng-event-source , который дает возможность предоставлять собственные заголовки HTTP.В обоих случаях происходит сбой сервера с непонятным сообщением об ошибке "npm ERR! code ELIFECYCLE npm ERR! errno 1
".
Чтобы избежать этой проблемы, я должен отключить ACL в моей модели.
2) Мне не удалось отправить пульс подключенным клиентам , и клиенты отключаются через X секунд.На самом деле EventSourcePolyfill
является вилкой этого пакета , который требует, чтобы сервер отправлял сообщения каждые X секунд в качестве пульса для обнаружения отключений.
Если я заменим EventSourcePolyfill
стандартным EventSource
Я могу получать сообщения с сервера, но клиенты не проходят проверку подлинности, поэтому каждый подключенный клиент получает одно и то же сообщение , а также я не могу обнаружить отключение клиента .
SERVER
/ server / models / my_model.js
{
"name": "MyModel",
"mixins": {
"AccessControl": false
},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"property": "createChangeStream",
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
/ server / boot / realtime.js
const es = require('event-stream');
module.exports = function(app) {
const myModel = app.models.MyModel;
myModel .createChangeStream(function(err, changes) {
changes.pipe(es.stringify()).pipe(process.stdout);
});
}
CLIENT
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { EventSourcePolyfill } from 'ng-event-source';
@Injectable()
export class ServerEventService {
protected apiServer = 'http://localhost:3000/';
getReservationStream(): Observable<any> {
return Observable.create((observer) => {
let eventSource = new EventSourcePolyfill (this.apiServer + 'api/MyModels/change-stream?_format=event-stream', { heartbeatTimeout: 5000, connectionTimeout: 5000});
eventSource.addEventListener('data', function (event) {
console.debug('Received event: ', event);
let json = JSON.parse(event.data);
observer.next(json);
});
eventSource.onerror = (error) => {
// readyState === 0 (closed) means the remote source closed the connection
if (eventSource.readyState === 0) {
console.log('The stream has been closed by the server.');
eventSource.close();
observer.complete();
} else {
observer.error('EventSource error: ' + error);
}
}
});
}
}
Заранее спасибо.
ОБНОВЛЕНИЕ 09/03/2019
Мне удалось решить вторую проблему, добавив Middelware в / server / server.js :
app.middleware('routes:before', function (req, res, next) {
if (req.path.indexOf('change-stream') !== -1) {
setInterval(() => {
let timestamp = +new Date();
res.write("heartbeat " + timestamp);
}, 20000);
}
next();
});