背景

最近做了一个微信小程序的即时通讯功能,之前我也做过 node.js 的 websocket 服务,不过是在 web 端应用的 socket.io 服务。小程序本身对 http、websocket 等连接均有诸多限制,所以这次项目选择了 node.js 自带的 ws 模块。

服务端

初始化一个 node.js 项目,引入 ws 模块

const webSocket = require('ws');
复制代码

创建 websocket 实例,并设置监听端口

const wss = new webSocket.Server({
    port: 3001
});
复制代码

定义 wss 实例方法,实现 socket 监听和信息发布。下面贴上简单的示例:

wss.on('connection', function connection(ws, req) {
    console.log('连接开启')
//发生错误
ws.on(<span class="hljs-string">'error'</span>, <span class="hljs-keyword">function</span> error(error) {
    console.log(<span class="hljs-string">'error'</span>, error);
});

//断开连接
ws.on(<span class="hljs-string">'close'</span>, <span class="hljs-keyword">function</span> close(close) {
    console.log( <span class="hljs-string">'已关闭'</span>);
});

ws.on(<span class="hljs-string">'message'</span>, <span class="hljs-keyword">function</span> message(message) {
    ws.send(<span class="hljs-string">'客户端发来了一条消息'</span>)
});

//发送消息
ws.send(<span class="hljs-string">'连接已开启'</span>);
ws.send(id + <span class="hljs-string">'已连接'</span>)

});

复制代码

这样,一个简单的 websocket 服务就配置完成了。当然,问题远远不止这么简单。要想在小程序中进行通信,还需要解决下面几个问题。

域名

关于小程序服务端域名配置,小程序开发文档中如下提到

小程序请求地址只支持 https 或者 wss 协议,因此首先要配置的就是 SSL 证书。拿到 SSL 证书之后,在服务端做一下 https 的配置即可。

var fs = require('fs');
const options = {
    key: fs.readFileSync('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'utf8'),//证书地址
    cert: fs.readFileSync('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'utf8'),//证书地址
};
var https = require('https');
var server = https.createServer(options, app);
复制代码

另外值得注意的是,websocket 监听的端口号需要做一下代理,因为小程序如果不配置端口号时,所有请求的 url 都不可以带端口号。

多房间通信

先看一下广播的实现:

//广播方法
wss.broadcast = function broadcast(data) {
    wss.clients.forEach(function each(client) {
        client.send(data)
    });
};
复制代码

wss 对象的 clients 是一个存储着所有 socket 连接对象的数组,每条连接对象都可以调用各自的 send 方法发送信息。

在此基础上,我们可以进行一定的封装,用一个唯一的标识符映射到每一条 socket 连接,这样我们需要向特定的某个连接发送信息时,就可以找到该连接。

可以通过连接的 url 作为唯一标识:

 let sockets = {}
 wss.on('connection', function connection(ws, req) {
        let id = req.url.slice(5);//截几位字符串根据自己实际获得的url来看
        sockets[id] = ws;
        ws.send(id + '已连接');
        ...
复制代码

客户端每次连接时 url 后拼接一个唯一 id,在服务端获取req.url并截取字符串拿到唯一 id,并将该连接对象存储在全局的 sockets 下以便需要时使用。

在此基础上,可以继续封装诸如加入房间、离开房间、房间内通信、向特定用户私聊等功能,总体来说是对 send 方法的封装。值得注意的是 send 方法只能发送字符串,json 对象需要转化成字符串再传入 send。

下面是一个私聊的示例:

wss.notice = function notice(id, data, ws) {
    // 向指定id发送
    try {
        ws.send('正在发送...')
        var notice = JSON.stringify({
            type: 'notice',
            data: data
        })
        let target = sockets[id]
        if (target) {
            target.send('收到一条新消息')
            target.send(notice)
        } else {
            ws.send('目标信道已关闭')
        }
    } catch (err) {
        console.log(err)
    }
}
复制代码

到这里,一个简单的聊天室服务端配置就基本完成了。

具体的代码细节,请观众老爷们移步微信小程序中聊天室的服务端和客户端配置示例^.^

  • Node.js

    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时。 Node.js 使用高效、轻量级的事件驱动、非阻塞 I/O 模型。Node.js 的生态系统是目前最大的开源包管理系统。 …

    58 引用
感谢    赞同    分享    收藏    关注    反对    举报    ...