【问题标题】:Why Angular observable based SseService works just once, receives events but produce first one为什么基于 Angular 可观察的 SseService 只工作一次,接收事件但产生第一个
【发布时间】:2020-05-05 12:43:34
【问题描述】:

我已使用此模式创建 ServerSentEvent 服务:Angular and Server Sent Events 这是服务代码:

import { Injectable, NgZone } from "@angular/core";
import { Observable } from "rxjs";

@Injectable({
  providedIn: "root"
})
export class SseService {
  constructor(private _zone: NgZone) { }

  getServerSentEvent(url: string): Observable<any> {
    return Observable.create(observer => {
      const eventSource = this.getEventSource(url);
      eventSource.onmessage = event => {
        this._zone.run(() => {
          observer.next(event.data);
          console.log(event); // Here I see every received  event
        });
      };
      eventSource.onerror = error => {
        this._zone.run(() => {
          observer.error(error);
          console.log(error);
        });
      };
      // return () => eventSource.close();
    });
  }

  private getEventSource(url: string): EventSource {
    return new EventSource(url);
  }
}

然后我在主组件中调用这个 ss-events 流:

ngOnInit() { //This subscribe works just for the first event no more
  this.sseService.getServerSentEvent("http://localhost:8080/ssevents")
    .subscribe(
      data => {
        this.eventmessage = data;
      },
      error => this.error = error
    );

  // But direct next EventSource onmessage() call works here: 
  this.source = new EventSource("http://localhost:8080/ssevents");
  this.source.onmessage = event => {
    this.zone.run(() => {
      this.eventmessage = event.data;
      console.log(event);
    });
  };
  this.source.onerror = error => {
    this.zone.run(() => {
      this.error = error.type;
      console.log(error);
    });
  };
}

为什么 sseservice 中的这个内部 observable 没有 作品?只是第一个。所以我需要使用第二个选项 - 但我在那里 收到永久错误 EventTarget(每秒或 半秒)没有理由 错误描述,除了 Type=error, EventPhase=2。但 接收到的事件,仅由服务器生成 插入 mongodb 后。

【问题讨论】:

  • 请修正格式
  • 我会很高兴 - 但如何呢?大概是第一个五花灰块不对,是不是第二个?例如,当添加代码块时 - Ctrl+ K 的安全性低于使用 {{ }} 来获得至少某种格式的文本块。而在第二个灰色块中,“”仍然围绕代码。

标签: angular observable eventsource


【解决方案1】:

可能有几个问题

  1. 尝试使用 addEventListener 而不是 onmessage
  2. 检查消息格式link
  3. 如果您移动了 6 个连接到同一主机 link,浏览器可能会中断连接

所以当你在测试时,你可以很快超越它

    @Injectable()
    export class SseService {
      private eventSource: EventSource;

      constructor(private zone: NgZone) {}

      getServerSentEvent(url: string): Observable<MessageEvent> {
        return Observable.create(observer => {
          const eventSource = this.getEventSource(url);
          eventSource.onopen = (ev) => {
            console.log('Connection to server opened.', ev);
          };
          eventSource.onerror = (ev) => {
            console.log('EventSource failed.', ev);
          };
          eventSource.addEventListener('message', event => {
            this.zone.run(() => {
              observer.next(event);
            });
          });
        });
      }

      private getEventSource(url: string): EventSource {
        if (this.eventSource) {
          console.log('EventSource closed.');
          this.eventSource.close();
        }
        this.eventSource = new EventSource(url);
        return this.eventSource;
      }
    }

我的测试example

【讨论】:

  • 已解决:由于存在 EventSource 错误的永久流,可能在重新连接后重新生成,传递给 Observable 错误回调,它解释了只有一个错误被传递给订阅者,并且没有数据 - 就像第一个之后一样错误 - 没有数据也没有错误!我在那里阅读后掌握了它:rxjs-dev.firebaseapp.com/guide/observable --“在可观察执行中,可能会传递零到无限的下一个通知。如果传递了错误或完成通知,那么之后就无法传递其他任何东西”。所以以前的状态只是由于可观察的执行
  • 确实,这个 sse 事件并不总是传递,因为我也在 Chrome 控制台中检查它。因此,如果我在一个 Chrome 浏览器窗口中触发事件,并在另一个 Chrome 浏览器窗口中接收 sse 事件,在另一个用户帐户下,会有这样的组合 - 从开发者控制台查看 - 发送窗口中的 sseevent ,接收时为 NO,发送时没有 -进入接收窗口,在 2 个窗口中没有 sseevents,在 2 个浏览器窗口中很少有 sseevents。我只需要接收,因此在实践中甚至更少 50% 的案例。可能是因为在 Heroku 上部署时互联网连接非常糟糕
  • 但是 2 周前,在部署到网络(云)之前,我在 localhost 上通过 Chrome REST 插件测试了这个事件。有一系列接收 sse 事件,但也有一系列不应该接收的事件,然后 - 再次出现。所以我认为这是由于一些缓存,当事件丢失时。但它可能与缓存无关。
  • 据我了解,EventSource 对服务器的调用存在永久循环(但为什么如果它是服务器发送的),当我看到此类消息时成功(带有此类消息编号的计数器)“EventSource 完成加载:GET “...app.herokuapp.com/ssseevent”。但是当我看到那个:“EventSource failed loading: GET”...app.herokuapp.com/sseevent”时,我明白在这种情况下没有 sse 事件可能,从服务器发送时???
  • 也可能是由于这种 EventSource “完成加载”的永久循环,频率为 0.5-1 s,它无法捕获所有 sse 事件,因为存在错误循环并且可能重新连接事件源。谁能给我解释一下机制???正如我解释的解决方案,但没有提供它 - 我只是在我的代码中的 EventSource onerorr() 中抛弃或注释了observer.error() - this._zone.run(() =&gt; { //observer.error(error); console.log(error); })
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-22
  • 2017-05-29
  • 2017-07-16
  • 1970-01-01
  • 1970-01-01
  • 2021-11-21
  • 2011-08-29
相关资源
最近更新 更多