文档中心 边缘应用 websocket交互迁移

websocket交互迁移

更新时间:2023-11-30 11:03:31

本章示例为将源站的Websocket逻辑搬到边缘执行,缩短交互时延,减少源压力。
代码说明:『边缘函数』返回一个包含Websocket客户端代码的HTML页面,它与『边缘函数』上的Websocket服务端交互。

详细代码

async function handleRequest(request) {
    let {pathname} = new URL(request.url)
    pathname = pathname.toLowerCase()
    if (pathname.endsWith('/')) {
        pathname = pathname.substring(0, pathname.length - 1);
    }
    
    if (pathname === '/wsclick.html') {
        return new Response(HOMEPAGE, {headers: {"Content-Type": "text/html; charset=utf-8"}})
    } else if (pathname === '/wsclick') {
        return websocketHandler(request) 
    }
}

async function websocketHandler(request) {
    const upgradeHeader = request.headers.get("Upgrade")
    if (upgradeHeader !== "websocket") {
        return new Response("Expected websocket", { status: 400 })
    }

    const [client, server] = Object.values(new WebSocketPair())
    let serverName = request.headers.get('x-ws-request-id')
    if (serverName) {
      serverName = serverName.match(/_(.*?)_/)[1]
    }
    await handleSession(server, serverName)

    return new Response(null, {
        status: 101,
        webSocket: client
    })
}

let count = 0

async function handleSession(websocket, serverName) {
    websocket.accept()
    websocket.addEventListener("message", async ({ data }) => {
        console.log('message', data)
        const now = (new Date()).toString().replace(' ()', '')
        if (data === "CLICK") {
            count += 1
            websocket.send(JSON.stringify({ count, tz: now, server: serverName }))
        } else {
            // An unknown message came into the server. Send back an error message
            websocket.send(JSON.stringify({ error: "Unknown message received", tz: now, server: serverName }))
        }
    })
  
    websocket.addEventListener("close", async evt => {
        // Handle when a client closes the WebSocket connection
        console.log('xxx:close', evt)
    })
}

const HOMEPAGE = `
<html>
<head>
<title>WebSocket点击次数示例</title>
<style>
  body {
    margin: 1rem;
    font-family: monospace;
    font-size: 16px;
  }
</style>
</head>
<body>
<p>点击次数: <span id="num"></span></p>
<button id="click">点击以向服务器发送消息,服务器将记录您的点击次数并反馈给您</button>

<p>您也可以发送WebSocket服务器无法识别的消息,这将导致WebSocket服务器向客户端返回一个error消息。</p>
<button id="unknown">模拟发送服务器无法识别的消息</button>

<p>完成测试后,可以点击下面按钮关闭连接。在刷新页面之前,进一步点击将不起作用。</p>
<button id="close">关闭连接</button>

<p id="error" style="color: red;"></p>

<h4>收到的服务器WebSocket消息</h4>
<ul id="events"></ul>

<script>
  let ws

  async function websocket(url) {
    ws = new WebSocket(url)

    if (!ws) {
      throw new Error("server didn't accept ws")
    }

    ws.addEventListener("open", () => {
      console.log('Opened websocket')
      updateCount(0)
    })

    ws.addEventListener("message", ({ data }) => {
      const { count, tz, error } = JSON.parse(data)
      addNewEvent(data)
      if (error) {
        setErrorMessage(error)
      } else {
        setErrorMessage()
        updateCount(count)
      }
    })

    ws.addEventListener("close", () => {
      console.log('Closed websocket')

      const list = document.querySelector("#events")
      list.innerText = ""
      updateCount(0)
      setErrorMessage()
    })
  }

  const url = new URL(window.location)
  url.protocol = "ws"
  url.pathname = "/wsclick"
  websocket(url)

  document.querySelector("#click").addEventListener("click", () => {
    ws.send("CLICK")
  })

  const updateCount = (count) => {
    document.querySelector("#num").innerText = count
  }

  const addNewEvent = (data) => {
    const list = document.querySelector("#events")
    const item = document.createElement("li")
    item.innerText = data
    list.prepend(item)
  }

  const closeConnection = () => ws.close()

  document.querySelector("#close").addEventListener("click", closeConnection)
  document.querySelector("#unknown").addEventListener("click", () => ws.send("HUH"))

  const setErrorMessage = message => {
    document.querySelector("#error").innerHTML = message ? message : ""
  }
</script>
</body>
</html>
`
                    
addEventListener("fetch", event => {
    return event.respondWith(handleRequest(event.request))
})
本篇文档内容对您是否有帮助?
有帮助
我要反馈
提交成功!非常感谢您的反馈,我们会继续努力做到更好!