在 redux-observable 中关闭 websocket 连接



我目前正在使用redux-observable来处理 websocket 连接,但无法弄清楚处理close事件的最佳方法是什么。

const webSocket$ = Observable.webSocket({
url: 'ws://localhost:8080'
});
export const fetchMessagesEpic = (action$) =>
action$.ofType(FETCH.MESSAGES)
.switchMap((action) =>
webSocket$
.catch((err) => { console.log(err);return true; }) <-- I can see the close event here
.map((msg) => addMessage(msg)));

我应该在catch中处理它(从那里发送一个新操作,然后在同一个史诗中使用takeUntil

来自 rxjs 的Observable.webSocket(又名 WebSocketSubject)仅在 CloseEvent 的wasClean值为 false 时将关闭事件发送到错误路径。

RXJS 源代码

socket.onclose = (e: CloseEvent) => {
this._resetState();
const closeObserver = this.closeObserver;
if (closeObserver) {
closeObserver.next(e);
}
//  v------------------------ Right here
if (e.wasClean) {
observer.complete();
} else {
observer.error(e);
}
};

因此,这意味着在您的情况下,连接未正确关闭。CloseEvent 上有时会有一个reason字段,可能会也可能不会为您提供见解,或者 Chrome 开发工具网络和控制台选项卡也可能有更多内容。

当远程服务器干净地关闭套接字时,执行特殊操作的正确方法是传入closeObserver。要么是直接{ next: func }观察者,要么更可能是主体(既是可观察量又是观察者)

// a stream of CloseEvents
const webSocketClose$ = new Subject();
const webSocket$ = Observable.webSocket({
url: 'ws://localhost:8080',
closeObserver: webSocketClose$
});
export const fetchMessagesEpic = (action$) =>
action$.ofType(FETCH.MESSAGES)
.switchMap((action) => {
const message$ = webSocket$
.map((msg) => addMessage(msg))
.catch((e) => Observable.of({
type: 'SOCKET_ERROR',
error: e
}));
const close$ = webSocketClose$
.take(1) // you probably only want one
.map((event) => ({
type: 'SOCKET_CLOSE_EVENT',
wasClean: event.wasClean,
code: event.code,
reason: event.reason
}));
return Observable.merge(message$, close$);
});

此代码做了几个假设:

  • 您要处理event.wasClean === true错误。此示例同时使用 closeObserver 和 catch,但您不必这样做。目前尚不清楚您是只关心不干净的关闭还是全部关闭。同样重要的是要知道,不干净的 CloseEvents 并不是 WebSocketSubject 可能引发的唯一错误。来自socket.onerror的错误以及JS异常被发送到那里。
  • 我们对webSocket$的订阅将在套接字关闭时完成(),它确实如此。如果没有,我们想要webSocket$.takeUntil(webSocketClose$).map(...)

另外,我想指出的是,rxjs 的 catch 运算符要求您返回一个可观察值,但您的示例返回了一个布尔值。这将产生错误。如果只想记录错误而不是处理错误,请使用do运算符。

// BAD
.catch((err) => { console.log(err);return true; })
// GOOD
.do({ error: (err) => console.log(err) })

最新更新