后端koa2前端ReactHooks中完成socket长连接(附源码)

后端koa2前端ReactHooks中完成socket长连接(附源码)

webSocket TCP长连接在平时中常用于一些高频前后端交互的场景,比如在线聊天、在线协作等;在以前时,一些项目中的通知与公告功能常用轮询来完成类webSocket的操作,但是这种方法频繁三次握手访问后端服务器,对服务器造成不小的压力,所以用webSocke长连接取代轮询是很有必要的;本次我就个人的开源项目里面的通知与公告功能来做案例,文章手把手帮您完成项目的socket的配置;项目源码在我个人的开源项目中,如果觉得可以,欢迎给作者收藏点赞~ 🥗

个人开源项目地址

一、了解socket.IO

一开始我个人是想选择koa-websocket的,但是实际使用后,发现这个文档不全、生态不够丰富,并且和我的项目并不是很契合,最终放弃了它,选择了socket.IOsocket.IO不仅官网文档很全,案例丰富,而且还特别契合我现在的项目,所以最终选择了它,实际使用感受确实好用;socket.IO是一个建立在webSocket协议上的库,它在服务器和客户端之间提供双向和低延迟的通信通道;

Socket.IO官方文档

二、koa2服务端使用socket.IO

2-1、安装

lua 复制代码
npm install socket.io

2-2、创建实例,并绑定到HTTP服务器

appuse注册页面,导入socket.iocreateServer创建实例绑定到HTTP服务器上,共用一个ip端口;cros解决跨域问题,io.of()配置独立的命名空间,.on监听连接事件,wsNotice是我个人封装的处理事件的函数;

ts 复制代码
import { Server } from 'socket.io' 

// ...中间一系列app.use注册,详细代码可下载源码查看

// 创建 Socket.IO 实例并绑定到 HTTP 服务器
const httpServer = createServer(app.callback())
const io = new Server(httpServer, {
  cors: {
    origin: '*',
    methods: ['GET', 'POST']
  }
})

// 在koa2应用中定义各种Socket.IO事件监听和处理
io.of('/wsNotice').on('connection', (socke封装t) => wsNotice(socket))

2-3、封装处理事件函数wsNotice

ts 复制代码
import SysNotice from '@/mysql/model/system/notice.model'
import { Socket } from 'socket.io'
import { DefaultEventsMap } from 'socket.io/dist/typed-events'
import { formatHumpLineTransfer } from '.'
import { queryConditionsData } from '../service'
import jwt from 'jsonwebtoken'
import env from '@/config/default'
import { IuserTokenType } from '@/types/auth'
import { judgeKeyOverdue } from './auth'

export const wsNotice = async (
  socket: Socket<DefaultEventsMap, DefaultEventsMap, DefaultEventsMap, any>
) => {
  const token = socket.handshake.query.token

  if (judgeToken(token as string)) {
    socket.on('postNotice', async (data) => {
      // 向所有的socket发送通知
      socket.broadcast.emit('getNotice', data)
      socket.emit('getNotice', data)

      // 向所有的socket更新通知公告
      socket.emit('getAllNotice', await getAllNoticeFn())
      socket.broadcast.emit('getAllNotice', await getAllNoticeFn())
    })

    socket.emit('getAllNotice', await getAllNoticeFn())

    socket.on('disconnect', (reason) => {
      console.log('socket已断开')
    })
  } else {
    socket.disconnect(true)
    console.error('token过期,断开socket连接')
  }
}

/**
 * 查询所有通知公告
 * @returns
 */
async function getAllNoticeFn() {
  return formatHumpLineTransfer(await queryConditionsData(SysNotice, { status: '0' }))
}

/**
 * 判断token是否有效
 * @param token
 * @returns
 */
async function judgeToken(token: string) {
  const user = jwt.verify(token, env().JWT_SECRET) as IuserTokenType
  return await judgeKeyOverdue(user.session)
}

其中向所有的socket连接发送消息,也可以选择使用socket.IO中的广播事件和房间,因为这里的需求很简单,所以就用最基本的操作了,可以按照自己的实际需求更改的哈~

三、ReactHooks客户端端使用socket.IO

客户端安装 socket.io-client 这个包,然后配置通信地址即可;

3-1、安装

lua 复制代码
npm install socket.io-client

3-2、封装创建socket的函数

tsx 复制代码
import useStore from '@/store'
import { InoticeType } from '@/type/modules/system/notice'
import { notification } from 'antd'
import { io } from 'socket.io-client'

const createSocket = (pathName: string) => {
  const {
    useSocketStore: { setNotices },
    useUserStore: { token },
  } = useStore()
  
  // forceNew开启命名空间,query携带用户token
  const socket = io(`${process.env.BASE_ENV}/${pathName}`, { forceNew: true, query: { token }})

  socket.on('connect', () => {
    console.log('socket是否连接成功' + socket.connected) // true
  })
  socket.on('connect_error', (err) => {
    console.log('socket连接失败', err)
    setTimeout(() => {
      socket.connect()
    }, 5000)
  })

  // 获取所有公告和通知
  socket.on('getAllNotice', (data: InoticeType[]) => {
    setNotices(data)
  })
  // 获取单条公告和通知
  socket.on('getNotice', (data: InoticeType) => {
    notification.info({
      message: data.noticeTitle,
      description: <div dangerouslySetInnerHTML={{ __html: data.noticeContent as string }} />,
    })
  })

  socket.on('disconnect', (reason) => {
    // 服务器断开socket连接时
    if (reason === 'io server disconnect') {
      socket.connect()
    }
    console.log('socket已断开', reason)
  })

  return socket
}

export default createSocket

3-3、在layout初始化的时候连接socket(地方可自行选择)

scss 复制代码
  useEffect(() => {
    // 初始化连接socket
    const socket = createSocket('wsNotice')
    // 存储socket实例,在通知模块,立即通知处需要用到socket.emit事件立即向所有用户发送通知信息
    setSocket(socket)
  }, [])

结语

以上用socket.IO完成最基础的通知与公告功能,如果自己有更复杂的业务,可以自行官网研究~🌮

相关推荐
SFLYQ16 分钟前
Go AICode 工具调研
后端
这里有鱼汤26 分钟前
Python模块化开发,从此告别乱糟糟的代码!
前端·后端·python
这里有鱼汤28 分钟前
高手也容易忽略的 Python 命名空间与作用域
前端·后端·python
捡田螺的小男孩29 分钟前
新来的技术总监,把DDD落地的那叫一个高级优雅!
java·后端
xiezhr1 小时前
程序员为什么总是加班?
前端·后端·程序员
猿java1 小时前
银行系统需要服务降级吗?
java·后端·面试
风象南1 小时前
SpringBoot实现单点登录(SSO)的4种方案
java·spring boot·后端
程序员一诺1 小时前
【Flask开发】嘿马文学web完整flask项目第3篇:2.用户认证,2.用户认证【附代码文档】
后端·python·flask·框架
慕容莞青9 小时前
MATLAB语言的进程管理
开发语言·后端·golang
陈明勇9 小时前
用 Go 语言轻松构建 MCP 客户端与服务器
后端·go·mcp