前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WebSocket协议-实战

WebSocket协议-实战

作者头像
数据小冰
发布2024-06-19 20:18:56
1120
发布2024-06-19 20:18:56
举报
文章被收录于专栏:数据小冰数据小冰

本文是WebSocket系列文章的第2篇,第1篇主要讲述概念原理。本文从实战角度介绍如何使用WebSocket。

Part1项目简介

本文实战项目来自Mastering WebSockets With Go。实现了一个精简版的Web聊天系统,前端采用 HTML+JS,后端用Go实现。注意:本文对原项目做了一点UI颜色调整

在本地构建部署后效果如下,先要登录后创建WebSocket连接,然后可以向聊天室发送信息。

Part2 关键API

1客户端API

下面是javascript创建WebSocket代码,直接通过构造函数 new WebSocket创建一个实例。

代码语言:javascript
复制
conn = new WebSocket("wss://" + document.location.host + "/ws?otp="+ otp);

            // Onopen
            conn.onopen = function (evt) {
                document.getElementById("connection-header").innerHTML = "Connected to Websocket: true";
            }

            conn.onclose = function(evt) {
                // Set disconnected
                document.getElementById("connection-header").innerHTML = "Connected to Websocket: false";
            }

            // Add a listener to the onmessage event
            conn.onmessage = function (evt) {
                console.log(evt);
                // parse websocket message as JSON
                const eventData = JSON.parse(evt.data);
                // Assign JSON data to new Event Object
                const event = Object.assign(new Event, eventData);
                // Let router manage message
                routeEvent(event);
            }

WebSocket构造函数

WebSocket接收一个URL参数,执行完下面语句后,就会与对应的host建立连接。

代码语言:javascript
复制
conn = new WebSocket("wss://" + document.location.host + "/ws?otp="+ otp)

onopen

WebSocket实例对象的onopen属性,在上面的连接建立成功后进行回调执行。

代码语言:javascript
复制
conn.onopen = function (evt) {
    document.getElementById("connection-header").innerHTML = "Connected to Websocket: true";
}

这里会在连接成功后,页面显示 "Connected to Websocket: true"

onmessage

收到来自服务端数据后的回调函数, 处理逻辑在routeEvent.

代码语言:javascript
复制
conn.onmessage = function (evt) {
    console.log(evt);
    // parse websocket message as JSON
    const eventData = JSON.parse(evt.data);
    // Assign JSON data to new Event Object
    const event = Object.assign(new Event, eventData);
    // Let router manage message
    routeEvent(event);
}

routeEvent先进行一些参数校验,然后构造messageEvent丢给appendChatMessage。

代码语言:javascript
复制
function routeEvent(event) {
    if (event.type === undefined) {
        alert("no 'type' field in event");
    }
    switch (event.type) {
        case "new_message":
        // Format payload
            const messageEvent = Object.assign(new NewMessageEvent, event.payload);
            appendChatMessage(messageEvent);
            break;
        default:
            alert("unsupported message type");
            break;
    }
}

真正显示处理在appendChatMessage函数。在消息前加上日期时间,并拼接到聊天室之前内容的尾部。

代码语言:javascript
复制
function appendChatMessage(messageEvent) {
    var date = new Date(messageEvent.sent);
    // format message
    const formattedMsg = `${date.toLocaleString()}: ${messageEvent.message}`;
    // Append Message
    textarea = document.getElementById("chatmessages");
    textarea.innerHTML = textarea.innerHTML + "\n" + formattedMsg;
    textarea.scrollTop = textarea.scrollHeight;
}

onclose

WebSocket连接关闭后的回调函数。在页面上显示"Connected to Websocket: false"。

代码语言:javascript
复制
conn.onclose = function(evt) {
    // Set disconnected
    document.getElementById("connection-header").innerHTML = "Connected to Websocket: false";
}

send

send方法向服务端发送数据。这里把payload数据封装成Event json格式发送给后端。

代码语言:javascript
复制
function sendEvent(eventName, payload) {
    // Create a event Object with a event named send_message
    const event = new Event(eventName, payload);
    // Format as JSON and send
    conn.send(JSON.stringify(event));
}

2服务端API

服务端采用的是开源的 github.com/gorilla/websocket。是用Go语言实现的WebSocket库。该库简单易用、性能比较高。

Upgrade

调用websocket.Upgrader对象的Upgrade方法将普通的HTTP连接升级为WebSocket连接。函数签名如下,直接将http的w和r传递给它即可。

代码语言:javascript
复制
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error)

url路由为/ws即走WebSocket协议,可以看到serveWS中调用 conn, err := websocketUpgrader.Upgrade(w, r, nil)将HTTP请求升级为WebSocket.

代码语言:javascript
复制
func (m *Manager) serveWS(w http.ResponseWriter, r *http.Request) {
 otp := r.URL.Query().Get("otp")
 if otp == "" {
  w.WriteHeader(http.StatusUnauthorized)
  return
 }

 if !m.otps.VerifyOTP(otp) {
  w.WriteHeader(http.StatusUnauthorized)
  return
 }

 log.Println("New connection")
 conn, err := websocketUpgrader.Upgrade(w, r, nil)
 if err != nil {
  log.Println(err)
  return
 }
 client := NewClient(conn, m)
 m.addClient(client)
 go client.readMessages()
 go client.writeMessages()
}

ReadMessage

调用ReadMessage读取客户端发送的数据,该方法返回3个参数,第一个参数表示读取的数据类型,第二参数是读取到的数据,第三个参数为error类型。

业务层面数据类型主要是 TextMessage 和 BinaryMessage,分别表示读取到数据是文本数据还是二进制数据。

WriteMessage

调用WriteMessage向客户端发送数据,需要传入两个参数,第一个参数表示数据类型,这里传输的是文本数据。第二个参数传数据内容。

Part3总结

服务端用短短的几百行代码实现了一个完整的WebSocket服务器框架,实现结构图如下,兼具安全性和扩展性,值得借鉴模仿。

以下几点内容值得学习:

  • 使用 Ping/Pong心跳技术保活
  • 限制消息大小避免恶意攻击
  • Origin Check 跨越检查
  • Authentication 身份验证
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据小冰 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Part1项目简介
  • Part2 关键API
    • 1客户端API
      • WebSocket构造函数
      • onopen
      • onmessage
      • onclose
      • send
    • 2服务端API
      • Upgrade
      • ReadMessage
      • WriteMessage
  • Part3总结
相关产品与服务
多因子身份认证
多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档