如何像使用axios一样使用Socket.IO实现请求与错误处理?
解决方案
服务端适配改造
核心逻辑是复用现有REST接口处理函数,无需重写业务代码,仅需要针对Socket.IO请求模拟Express的req、res对象,通过Socket.IO自带的ack回调机制返回响应即可。
完整服务端代码示例
// 引入你原有业务的post相关处理函数 const { postCreate, postList, postUpdate, postDelete } = require('./controllers/post') io.on('connection', socket => { console.log('User is connected on socket'); // 统一监听post类请求,约定事件名为`post:request` socket.on('post:request', async (method, path, data, callback) => { // 1. 模拟Express的req对象,结构和原有REST请求的req完全对齐 const req = { body: data, user: socket.user, // socket.user为Socket连接鉴权后挂载的用户信息,和原有req.user一致 query: method === 'GET' ? data : {}, params: {} // 若路径带参数可自行解析后挂载 } // 2. 模拟Express的res对象,适配原有处理函数的status、json方法 const res = { status(code) { this.statusCode = code return this }, json(payload) { // 调用Socket的ack回调把结果返回给客户端 callback({ status: this.statusCode || 200, data: payload }) } } // 3. 匹配路由对应处理函数,和你原有REST路由规则对齐 try { if (method === 'POST' && path === '/post/create') return postCreate(req, res) if (method === 'GET' && path === '/post/list') return postList(req, res) if (method === 'PUT' && path === '/post/update') return postUpdate(req, res) if (method === 'DELETE' && path === '/post/delete') return postDelete(req, res) // 未匹配到路由返回404 res.status(404).json({ error: '接口不存在' }) } catch (err) { // 捕获全局异常返回500 res.status(500).json({ error: '服务端内部错误' }) } }) socket.on('disconnect', () => console.log('disconnected')) })
补充鉴权适配
和原有REST接口的token鉴权逻辑对齐即可:
- 客户端初始化Socket时在auth字段携带token:
const socket = io(服务端地址, { auth: { token: localStorage.getItem('token') } })
- 服务端校验token合法性后,把用户信息挂载到
socket.user上,和原有Express鉴权中间件逻辑保持一致。
客户端封装改造
基于全局挂载的Socket实例,封装和axios调用方式完全一致的工具,返回Promise实例支持.then()、.catch()链式调用。
封装工具代码
// 单独封装为socketApi.js import { useContext } from 'react' import { AuthContext } from './你的AuthContext文件路径' export const useSocketApi = () => { const { socket } = useContext(AuthContext) // 通用请求方法 const request = (method, path, data = {}) => { return new Promise((resolve, reject) => { // 发送Socket请求,等待服务端ack回调 socket.emit('post:request', method, path, data, (res) => { // 和axios逻辑对齐:2xx状态码视为成功,其余视为失败 if (res.status >= 200 && res.status < 300) { resolve(res.data) } else { // 错误结构和原有axios catch返回的结构完全对齐 reject({ response: res, message: res.data.error || '请求失败' }) } }) }) } // 暴露四个方法,调用规则和axios完全一致 return { get: (path, params) => request('GET', path, params), post: (path, data) => request('POST', path, data), put: (path, data) => request('PUT', path, data), delete: (path, data) => request('DELETE', path, data) } }
调用示例
和原有axios的使用方式完全相同,不需要修改业务逻辑:
// 组件内调用 const socketApi = useSocketApi() socketApi.post('/post/create', { title: '测试', content: '测试内容' }) .then(post => { // 原有axios then的逻辑直接复用 console.log('创建成功', post) }) .catch(err => { // 原有axios catch的逻辑直接复用 console.error('创建失败', err.message) })
原有监听逻辑修复
你之前的useEffect缺少依赖数组,每次组件渲染都会触发Socket断开重连,修改为:
const {socket} = useContext(AuthContext); useEffect(() => { socket.on("connect", () => { console.log("client connected") }) // 不要在业务组件内调用socket.disconnect(),全局Socket保持长连接即可,仅在用户登出时断开 }, [socket])
内容的提问来源于stack exchange,提问作者Rajanboy
相关产品推荐
相关产品推荐

