Hapi.js 完成 IM 聊天系统开发 - 遇到的 WebSocket 长连接问题解决

阅读时长 9 分钟读完

随着移动互联网的普及,即时通讯成为了人们生活中不可或缺的一部分,因此,怎样开发高效、稳定、快速的聊天系统成为了前端工程师面临的重要问题。本文将针对前端类相关人员介绍如何使用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聊天系统。为了实现一个完整的聊天系统,我们的应用需要包含以下几部分:

  1. 初始化应用
  2. 路由处理以及API注册
  3. 客户端UI设计
  4. 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文件也更加易于控制。下面是一些相对完整的代码示例:

服务器

这里是服务器端代码,其中需注意以下几点:

  1. 应用层也可以使用名为wss(Of course, it’s Secure WebSocket)的加密版本
  2. 请务必设置PingIntertval和PongTimeout,以便在例外情况下关闭非法连接
  3. Socket中的建立与处理是异步的,我们在“socket.on()”或者“socket.emit()”后面放置应许的回调方法来进行处理
-- -------------------- ---- -------
----- ------ - --- ------------- ----- ---- ---
--------------
    ------- ------
    ---------
    -------- -------- ----- -- -
        ------ -----------------------
    -
---

----- -- - ------------------------- -
    ------------- -----
    ------------ ----
---

------------------- ----- -------- -------- -

    ------------------- -----------
    ----------------------- -------- -- -
        ------------------- ---------------
    ---

    -------------------- -------- --------- -
        ------------------- ----- -------------
    ---

    ----- ---- - -----------
    ------------------- ------

---
展开代码

客户端

在Socket.IO中,客户端的调用方法是一样的。不同之处在于,客户端的初始化中应该使用socketio.js并将其添加到HTML页面中。如下所示:

Hapi.js框架的,Server端开发中如何注册WebSocket服务

使用Hapi.js框架,我们可以通过插件的方式来完成WebSocket服务的注册,示例代码如下:

-- -------------------- ---- -------
----- ---- - ----------------------
----- -------- - ---------------------

----- ----- - ----- -- -- -
  ----- ------ - -------------
    ----- ------------
    ----- ----
  ---
  
  ----- ---------------
  ------------------- ------- - ---------------------

  ----- -- - --------------------------
  ------------------- ------ -- -
    ------------------- --------- -- ---------
    ----------------------- -- -- ------------------- ------------ ---- ----------

    --------------- ------- -- -
        ------------
    ---
  ---

  ------ -------
-

-------------- - --------
展开代码

长连接遇到的问题及解决方案

在WebSocket长连接过程中,我们可能会遇到以下诸多问题:连接的不稳定、频繁的心跳包请求等等。接下来我们会对上述问题进行详细的阐述,并分享一下解决方案。

连接的不稳定

连接不稳定是长连接常常遇到的问题,其中一种原因是因为,Websockets长连接在运行的时候需要经过TCP/IP网络的传输,而网络质量或服务的不稳定性可能导致连接中断或无法建立连接。在Hapi.js中实现WebSocket长连接时,我们可通过设置“pingTimeout”与“pingInterval”属性的方式,提高连接的稳定性。

对于上述代码而言,我们对websocket连接的空闲时间和发送ping消息的频率进行了设定,并尝试使pingInterval参数的值小于pingTimeout的值。

频繁的心跳包请求

频繁的心跳包请求可能会给服务器带来较大的负担,并导致端口被占用等问题。为了进行优化,我们在检查消息内容时,对于不在指定内容范围的消息,可以直接忽略。此外,我们也可以把需要进行传输的内容进行分包,较小的包对于服务器的处理较为通畅。

-- -------------------- ---- -------
--------------- ----------------- -
    -- -------- --- ------- -
        --------------------
        -------
    -

    ----- --- - ---------------
    --- --- - --
    ----- ---- - ---- -
        ----- ---- - ------------- --- - -----
        ----------------- ------------------- -------
        --- -- -----
    -
---
展开代码

上述代码中,当客户端发来的消息为"ping"时,服务器会通过发送"pong"来回应心跳包请求。此外,对于消息内容长度较大的情况,我们会按大小进行分包,以减轻服务器负担。

至此,我们就完成了使用Hapi.js框架开发IM聊天系统的整个过程,以及长连接问题解决方案的分享。鉴于此,我们对Hapi.js框架和WebSocket协议的应用和理解都有了一个更深层次的认识,期望本篇文章能对前端开发人员有所帮助。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67c831d5e46428fe9ee65c60

纠错
反馈

纠错反馈