首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >角8-处理SSE错误重新连接

角8-处理SSE错误重新连接
EN

Stack Overflow用户
提问于 2019-09-24 07:46:32
回答 1查看 2.9K关注 0票数 8

我正在研究一个角8(带有电子6和离子4)项目,现在我们正在进行评估阶段,我们正在决定是用SSE (服务器发送的事件)还是Web来代替轮询。我的工作是研究SSE。

我创建了一个小的快速应用程序,它可以生成随机数,而且都工作得很好。唯一困扰我的是在服务器错误时重新连接的正确方法。

我的实现如下所示:

代码语言:javascript
运行
复制
  private createSseSource(): Observable<MessageEvent> {
    return Observable.create(observer => {
      this.eventSource = new EventSource(SSE_URL);
      this.eventSource.onmessage = (event) => {
        this.zone.run(() => observer.next(event));
      };

    this.eventSource.onopen = (event) => {
      console.log('connection open');
    };

    this.eventSource.onerror = (error) => {
      console.log('looks like the best thing to do is to do nothing');
      // this.zone.run(() => observer.error(error));
      // this.closeSseConnection();
      // this.reconnectOnError();
    };
  });
}

我试图在这个reconnectOnError()之后实现answer函数,但是我无法使它工作。然后我放弃了reconnectOnError()函数,这似乎是一件更好的事情。不要试图关闭和重新连接,也不要将错误传播到可观察的位置。只要坐着等待,当服务器再次运行时,它将自动重新连接。

的问题是,这真的是最好的做法吗?最重要的一点是,FE应用程序与它自己的服务器进行通信,该服务器不能被应用程序的另一个实例(内置设备)访问。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-28 05:55:15

我看到我的问题得到了一些关注,所以我决定张贴我的解决方案。回答我的问题:“这真的是最好的做法吗,省略重新连接功能?”我不知道:)。但是这个解决方案对我有效,并且在生产中得到了证明,它提供了如何在某种程度上实际控制SSE重新连接的方法。

我所做的是:

void

  • Instead

  • 重写了createSseSource函数,因此返回类型是返回可观测的,来自
  1. 的数据被输入到subjects/NgRx actions
  2. 添加了公共openSseChannel和私有reconnectOnError函数以更好地处理
  3. 私有函数processSseEvent来处理自定义消息类型

G 214

因为我在这个项目上使用了NgRx,所以每个SSE消息都会发出相应的操作,但是可以用ReplaySubject替换它,并将其公开为observable

代码语言:javascript
运行
复制
// Public function, initializes connection, returns true if successful
openSseChannel(): boolean {
  this.createSseEventSource();
  return !!this.eventSource;
}

// Creates SSE event source, handles SSE events
protected createSseEventSource(): void {
  // Close event source if current instance of SSE service has some
  if (this.eventSource) {
    this.closeSseConnection();
    this.eventSource = null;
  }
  // Open new channel, create new EventSource
  this.eventSource = new EventSource(this.sseChannelUrl);

  // Process default event
  this.eventSource.onmessage = (event: MessageEvent) => {
    this.zone.run(() => this.processSseEvent(event));
  };

  // Add custom events
  Object.keys(SSE_EVENTS).forEach(key => {
    this.eventSource.addEventListener(SSE_EVENTS[key], event => {
      this.zone.run(() => this.processSseEvent(event));
    });
  });

  // Process connection opened
  this.eventSource.onopen = () => {
    this.reconnectFrequencySec = 1;
  };

  // Process error
  this.eventSource.onerror = (error: any) => {
    this.reconnectOnError();
  };
}

// Processes custom event types
private processSseEvent(sseEvent: MessageEvent): void {
  const parsed = sseEvent.data ? JSON.parse(sseEvent.data) : {};
  switch (sseEvent.type) {
    case SSE_EVENTS.STATUS: {
      this.store.dispatch(StatusActions.setStatus({ status: parsed }));
      // or
      // this.someReplaySubject.next(parsed);
      break;
    }
    // Add others if neccessary
    default: {
      console.error('Unknown event:', sseEvent.type);
      break;
    }
  }
}

// Handles reconnect attempts when the connection fails for some reason.
// const SSE_RECONNECT_UPPER_LIMIT = 64;
private reconnectOnError(): void {
  const self = this;
  this.closeSseConnection();
  clearTimeout(this.reconnectTimeout);
  this.reconnectTimeout = setTimeout(() => {
    self.openSseChannel();
    self.reconnectFrequencySec *= 2;
    if (self.reconnectFrequencySec >= SSE_RECONNECT_UPPER_LIMIT) {
      self.reconnectFrequencySec = SSE_RECONNECT_UPPER_LIMIT;
    }
  }, this.reconnectFrequencySec * 1000);
}

由于SSE事件被输入到subject/actions中,所以连接是否丢失并不重要,因为至少在subject或存储中保留了最后一个事件。然后,重新连接的尝试就会悄然发生,当新的数据被发送时,就会无缝地处理。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58075434

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档