随着移动互联网的普及,即时通讯成为了人们生活中不可或缺的一部分,因此,怎样开发高效、稳定、快速的聊天系统成为了前端工程师面临的重要问题。本文将针对前端类相关人员介绍如何使用Hapi.js框架完成IM聊天系统的开发,并着重分享通过Hapi.js框架开发遇到的WebSocket长连接问题的解决方案。
Hapi.js 框架介绍
Hapi.js是一款快速、可靠、可扩展、自定义程度高的Node.js框架,它致力于让我们可以更易构建 enterprise级别的应用,其主要特点如下:
- 支持插件化,扩展性很好
- 提供了强大的路由,默认支持各类HTTP请求的处理以及Websocket双向通信
- 充分考虑了安全性,提供了诸如跨站点请求伪造(CSRF)、跨站点脚本攻击(XSS)、HTTP响应头注入、HTTP公共流量盗用等一系列安全防护功能
- 内置了完善的运行环境,比如缓存、页面渲染和模板支持等等
基于上述特点,Hapi.js成为了Node.js开发的一款常见框架,且有不少的应用场景。
IM 聊天系统开发
下面我们来创建一个IM聊天系统。为了实现一个完整的聊天系统,我们的应用需要包含以下几部分:
- 初始化应用
- 路由处理以及API注册
- 客户端UI设计
- WebSocket长连接处理
初始化应用
我们首先需要初始化一个hapi.js应用,示例代码如下:
-- -------------------- ---- ------- ----- ---- - ---------------------- ----- ---- - ----- -- -- - ----- ------ - --- ------------- ----- ----- ----- ----------- --- ----- --------------- ------------------- ------- -- ---- ----------------- -- -------------------------------- ----- -- - ----------------- ---------------- --- -------展开代码
在起步应用中简单的设置了应用的主机和端口。值得注意的是:Hapi.js框架基于Async/Await来进行异步处理,使用时需要配合使用async + await或者Promise。
路由处理以及API注册
路由是我们在Hapi.js应用中编写的HTTP请求处理的方法,所以我们需要在此创建一个路由来处理从客户端发送过来的HTTP请求。我们将在后面的WebSocket部分中展开讲述如何将WebSocket注册为路由来处理。在此,我们先来一个简单的路由请求的示例代码:
-- -------------------- ---- ------- ----- ---- - ---------------------- ----- ---- - ----- -- -- - ----- ------ - --- ------------- ----- ----- ----- ----------- --- -------------- ------- ------ --------- -------- --------- -- -- - ------ ------ -------- - --- ----- --------------- ------------------- ------- -- ---- ----------------- -- -------------------------------- ----- -- - ----------------- ---------------- --- -------展开代码
在此示例中,我们对"route"方法的调用进行了简要定义,其中对应的http请求方法为GET。应用首先会接收到来自客户端的GET请求,之后,router获得该请求,执行对应的方法,最后将结果返回客户端。
客户端UI设计
在完成上述内容后,我们开始着手设计一个优秀的用户交互界面。由于该文章的主要内容是WebSocket长连接的处理,所以这里将不在多加赘述。
WebSocket长连接处理
接下来,我们来讲述一下在Hapi.js框架中如何使用websocket长连接,并简述不同websocket库的异同。
WebSocket长连接的异同
最先被大众所熟知的WebSocket库是SockJS,而后出现的Engine.IO在某些情况下更强大。另外,尽管现在的WebSocket库的多样性相对较多,但这里将我们会着重介绍最常用和最实用的Socket.IO库。
Socket.IO支持前后端的双向通讯,拓展了SockJS和Engine.IO并在它们的基础上重构,为我们的应用层提供了一个更健全的、适用于生产者环境的实现,相比之下其中所需的JavaScript文件也更加易于控制。下面是一些相对完整的代码示例:
服务器
这里是服务器端代码,其中需注意以下几点:
- 应用层也可以使用名为wss(Of course, it’s Secure WebSocket)的加密版本
- 请务必设置PingIntertval和PongTimeout,以便在例外情况下关闭非法连接
- Socket中的建立与处理是异步的,我们在“socket.on()”或者“socket.emit()”后面放置应许的回调方法来进行处理
-- -------------------- ---- ------- ----- ------ - --- ------------- ----- ---- --- -------------- ------- ------ --------- -------- -------- ----- -- - ------ ----------------------- - --- ----- -- - ------------------------- - ------------- ----- ------------ ---- --- ------------------- ----- -------- -------- - ------------------- ----------- ----------------------- -------- -- - ------------------- --------------- --- -------------------- -------- --------- - ------------------- ----- ------------- --- ----- ---- - ----------- ------------------- ------ ---展开代码
客户端
在Socket.IO中,客户端的调用方法是一样的。不同之处在于,客户端的初始化中应该使用socketio.js并将其添加到HTML页面中。如下所示:
const socket = io.connect('http://localhost:3000'); socket.on('time', function (time) { console.log(`Server time: ${time}`); socket.emit('message', 'Hi, Server!'); });
Hapi.js框架的,Server端开发中如何注册WebSocket服务
使用Hapi.js框架,我们可以通过插件的方式来完成WebSocket服务的注册,示例代码如下:
-- -------------------- ---- ------- ----- ---- - ---------------------- ----- -------- - --------------------- ----- ----- - ----- -- -- - ----- ------ - ------------- ----- ------------ ----- ---- --- ----- --------------- ------------------- ------- - --------------------- ----- -- - -------------------------- ------------------- ------ -- - ------------------- --------- -- --------- ----------------------- -- -- ------------------- ------------ ---- ---------- --------------- ------- -- - ------------ --- --- ------ ------- - -------------- - --------展开代码
长连接遇到的问题及解决方案
在WebSocket长连接过程中,我们可能会遇到以下诸多问题:连接的不稳定、频繁的心跳包请求等等。接下来我们会对上述问题进行详细的阐述,并分享一下解决方案。
连接的不稳定
连接不稳定是长连接常常遇到的问题,其中一种原因是因为,Websockets长连接在运行的时候需要经过TCP/IP网络的传输,而网络质量或服务的不稳定性可能导致连接中断或无法建立连接。在Hapi.js中实现WebSocket长连接时,我们可通过设置“pingTimeout”与“pingInterval”属性的方式,提高连接的稳定性。
const io = SocketIo(server.listener, { pingTimeout: 5000, // 连接的空闲时间超过该时间,便会关闭 WebSocket 长连接 pingInterval: 25000, // 向客户端发送 ping 消息的持续时间,一般应该小于 pingTimeout });
对于上述代码而言,我们对websocket连接的空闲时间和发送ping消息的频率进行了设定,并尝试使pingInterval参数的值小于pingTimeout的值。
频繁的心跳包请求
频繁的心跳包请求可能会给服务器带来较大的负担,并导致端口被占用等问题。为了进行优化,我们在检查消息内容时,对于不在指定内容范围的消息,可以直接忽略。此外,我们也可以把需要进行传输的内容进行分包,较小的包对于服务器的处理较为通畅。
-- -------------------- ---- ------- --------------- ----------------- - -- -------- --- ------- - -------------------- ------- - ----- --- - --------------- --- --- - -- ----- ---- - ---- - ----- ---- - ------------- --- - ----- ----------------- ------------------- ------- --- -- ----- - ---展开代码
上述代码中,当客户端发来的消息为"ping"时,服务器会通过发送"pong"来回应心跳包请求。此外,对于消息内容长度较大的情况,我们会按大小进行分包,以减轻服务器负担。
至此,我们就完成了使用Hapi.js框架开发IM聊天系统的整个过程,以及长连接问题解决方案的分享。鉴于此,我们对Hapi.js框架和WebSocket协议的应用和理解都有了一个更深层次的认识,期望本篇文章能对前端开发人员有所帮助。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67c831d5e46428fe9ee65c60