我正在开发一个需要使用websocket的项目,因此服务器可以快速将数据推送到Web UI。我正在使用Angular v5和angular-cli。但是,当它失败时,我很难让websocket连接重试。
对于那些感兴趣的人,可以找到当前状态的项目here。
我跟着this tutorial但是还没有真正掌握rxjs原则。我一直在做很多试验和错误。我现在在哪里。
所以我创建了一个websocket服务来设置Observable
:
export class WebsocketService {
constructor() { }
private subject: Rx.Subject<MessageEvent>;
public connect(url): Rx.Subject<MessageEvent> {
if (!this.subject) {
this.subject = this.create(url);
}
return this.subject;
}
private create(url): Rx.Subject<MessageEvent> {
let ws = new WebSocket(url);
let observable = Rx.Observable.create(
(obs: Rx.Observer<MessageEvent>) => {
ws.onmessage = obs.next.bind(obs);
ws.onerror = obs.error.bind(obs);
ws.onclose = obs.complete.bind(obs);
return ws.close.bind(ws);
})
let observer = {
next: (data: Object) => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(data));
}
}
}
return Rx.Subject.create(observer, observable);
}
}
然后RaceDataService
使用WebSocketService
将数据映射到有用的地方:
export class RaceDataService {
public dataStream: Subject<any>;
constructor(wsService: WebsocketService) {
this.dataStream = <Subject<any>>wsService
.connect(ETS_URL)
.map((response:any): any => {
let data = JSON.parse(response.data);
return data
})
.retry(3)
}
sendAction(action:WebsocketAction) {
this.dataStream.next(action);
}
}
最后,我订阅了race-display
组件中的observable,如下所示:
constructor(private raceDataService:RaceDataService) {
raceDataService.dataStream.subscribe(
msg => {
console.log("Response from websocket: ");
console.log(msg);
if(msg.RaceData) {
this.HandleCurrentRaceData(msg.RaceData);
}
},
err => {
this.isConnected = false;
},
() => {
this.sessionEnded = true;
}
)
}
根据我的阅读,在设置可观察对象之后放置.retry(3)
应确保在失败后重试连接3次。最终这还不够,我将不得不使用retryWhen()
做一些更高级的东西,但此时这个简单的重试甚至不起作用,websocket连接只是尝试了一次而且就是这样。
我真的很感激任何指示。
答案 0 :(得分:1)
注意在SO问题WebSocket: How to automatically reconnect after it dies中,他们谈到套接字关闭时重新连接。
在您的代码中,retry(3)
仅响应通过行ws.onerror = obs.error.bind(obs)
发生的事件,但这些只会是套接字处于活动状态时 发生的错误< / EM> 即可。
要使用Rx.retry()重试连接错误,您可能会尝试将websocket onClose挂钩到可观察的onError(ws.onclose = obs.error.bind(obs);
),但Rx.retry()只会重新运行wsService.connect(ETS_URL)
,它将返回主题,它(因为它现在被实例化)不会调用wsService.create()
来执行重新打开。
我认为你必须处理websocket级别的重试,而不是在可观察的级别 - 使用附加到onclose的函数,根据引用的问题:
ws.onclose = function(e) {
console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
setTimeout(function() {
connect();
}, 1000);
};
因此,您有三种类型的错误:
1)重新打开过早关闭的连接
2)重试失败的初始打开,你需要在let ws = new WebSocket(url)
周围尝试.catch。
3)ws.onerror
发出的连接期间发生的错误。我不确定它们是什么,所以不确定当前的策略(将它们传递给observable)是否最好。请注意,可观察流上的错误将关闭流,因此如果ws错误可忽略(即发生错误消息但后续消息正常),则您不希望流关闭。 / p>