后端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完成最基础的通知与公告功能,如果自己有更复杂的业务,可以自行官网研究~🌮

相关推荐
ss2731 小时前
基于Springboot + vue实现的中医院问诊系统
java·spring boot·后端
猫头虎2 小时前
如何解决IDE项目启动报错 error:0308010C:digital envelope routines::unsupported 问题
javascript·ide·vue.js·typescript·node.js·编辑器·vim
左灯右行的爱情2 小时前
Redis 缓存并发问题深度解析:击穿、雪崩与穿透防治指南
java·数据库·redis·后端·缓存
南玖yy3 小时前
C++ 成员变量缺省值:引用、const 与自定义类型的初始化规则详解,引用类型和const类型的成员变量自定义类型成员是否可以用缺省值?
c语言·开发语言·c++·后端·架构·c++基础语法
不爱总结的麦穗3 小时前
面试常问!Spring七种事务传播行为一文通关
后端·spring·面试
小虚竹3 小时前
claude 3.7,极为均衡的“全能型战士”大模型,国内直接使用
开发语言·后端·claude·claude3.7
Yharim4 小时前
两个客户端如何通过websocket通信
spring boot·后端·websocket
bcbnb4 小时前
iOS 性能调优实战:三款工具横向对比实测(含 Instruments、KeyMob、Xlog)
后端
极客智谷4 小时前
Spring AI应用系列——基于ARK实现多模态模型应用
人工智能·后端
啊花是条龙4 小时前
使用 Axios 和 AbortController 实现请求控制和取消
react.js·typescript