后端koa2前端ReactHooks中完成socket长连接(附源码)
webSocket TCP
长连接在平时中常用于一些高频前后端交互的场景,比如在线聊天、在线协作等;在以前时,一些项目中的通知与公告功能常用轮询来完成类webSocket
的操作,但是这种方法频繁三次握手访问后端服务器,对服务器造成不小的压力,所以用webSocke
长连接取代轮询是很有必要的;本次我就个人的开源项目里面的通知与公告功能来做案例,文章手把手帮您完成项目的socket
的配置;项目源码在我个人的开源项目中,如果觉得可以,欢迎给作者收藏点赞~ 🥗
一、了解socket.IO
一开始我个人是想选择koa-websocket
的,但是实际使用后,发现这个文档不全、生态不够丰富,并且和我的项目并不是很契合,最终放弃了它,选择了socket.IO
,socket.IO
不仅官网文档很全,案例丰富,而且还特别契合我现在的项目,所以最终选择了它,实际使用感受确实好用;socket.IO
是一个建立在webSocket
协议上的库,它在服务器和客户端之间提供双向和低延迟的通信通道;
二、koa2服务端使用socket.IO
2-1、安装
lua
npm install socket.io
2-2、创建实例,并绑定到HTTP服务器
在app
的use
注册页面,导入socket.io
,createServer
创建实例绑定到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
完成最基础的通知与公告功能,如果自己有更复杂的业务,可以自行官网研究~🌮