关于 websocket 和 loction.replace 的问题

Question about websocket and loction.replace

我尝试用Deno ws重新加载文档,但是第二次重新加载后会报错
Uncaught ConnectionReset: Socket has already been closed throw new Deno.errors.ConnectionReset("Socket has already been closed");

var ws = new WebSocket("ws://127.0.0.1:8080/ws")
    ws.onopen = function () {
      ws.send('ws open')
      console.log('ws open');
    }
    ws.addEventListener("message", (e) => {
      if (e.data === 'fileUpdate') {
        // ws.send('close')
        location.replace(location.href);
      }
    })

似乎location.replace(location.href) 引发错误 有什么解决办法吗?

这是 Deno 代码:

import { Application } from "https://deno.land/x/abc/mod.ts"; 
import { acceptWebSocket } from "https://deno.land/std@0.51.0/ws/mod.ts";
new Application()
  .file("/", "./index.html")
  .file("/module.js", "./module.js")
  // .file("sw.js", "ServiceWorker.js")

  .get('/ws', async (c: any) => {
    const { conn, headers, r: bufReader, w: bufWriter } = c.request;
    const ws = await acceptWebSocket({
      conn,
      headers,
      bufReader,
      bufWriter,
    });
    for await (const e of ws) {
      if (e === 'close') {
        ob.remove("fileUpdate")
        continue
      }
      ob.on("fileUpdate", () => {
        ws.send("fileUpdate")
      })
    }
  })
  .start({ port: 8080 })

ob 像这样:

class Ob {
  private list: ObList[] = []
  send(event: string) {
    this.list.forEach((e: ObList) => {
      if (e.event === event) {
        e.cb && e.cb()
      }
    })
  }
  on(event: string, cb: Function) {
    this.list.push({ event, cb })
  }
  remove(event:string){
    this.list=this.list.filter((e:ObList)=>{
      return e.event!==event
    })
  }
}

框架是abc

发生错误是因为您在套接字关闭后发送消息。

当您这样做时:location.replace(location.href); 刷新页面并关闭当前套接字。

您可以捕获错误,或在发送消息前检查 ws.isClosed

for await (const e of ws) {
  if (e === 'close') {
    ob.remove("fileUpdate")
    continue
  }
  ob.on("fileUpdate", () => {
    console.log('sending')
    if(!ws.isClosed)
       ws.send("fileUpdate")
  })
}

虽然这会修复错误,但无法解决问题的根源。您的 ob.on('fileUpdate') 事件在 套接字关闭后 触发。您应该清除 WebSocket 关闭事件上的监听器,您可以使用 ws.isWebSocketCloseEvent

import { acceptWebSocket, isWebSocketCloseEvent } from "https://deno.land/std@0.51.0/ws/mod.ts";
/* ... */
for await (const e of ws) {
  if(isWebSocketCloseEvent(e) || e === 'close') {
    // clear listeners here
    ob.remove("fileUpdate")
    // if e === 'close' you may want to close the socket
  }
}