Socket IO传输Date自动转为字符串,如何实现直接使用无需转换?
解决Socket.io中Date对象自动转为字符串的问题
这个问题我之前也碰到过——本质是JSON本身没有原生的Date类型支持,Socket.io默认用JSON序列化数据,所以Date对象会被转成ISO格式的字符串,不管是服务器往客户端发、客户端往服务器发,还是通过回调返回的Date,都会出现这个情况。不过有几种不用每次手动new Date()的解决方案,看你需求选:
方案1:全局自定义序列化/反序列化逻辑(最省心)
Socket.io允许你替换默认的解析器逻辑,通过自定义reviver(反序列化时用)和replacer(序列化时用)函数,让Date对象在传输前后自动转换,全局生效,不用改业务代码。
服务器端代码示例:
const { Server } = require('socket.io'); // 创建Socket.io服务器时配置自定义parser const io = new Server({ parser: { // 反序列化:把ISO日期字符串转回Date对象 reviver: (key, value) => { // 用正则匹配标准ISO日期格式(比如2024-05-20T12:34:56.789Z) if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value)) { return new Date(value); } return value; }, // 序列化:把Date对象转成ISO字符串 replacer: (key, value) => { if (value instanceof Date) { return value.toISOString(); } return value; } } }); // 之后正常emit或用回调返回Date就行 io.on('connection', (socket) => { // 示例1:服务器主动发Date socket.emit('current-time', new Date()); // 示例2:客户端请求后回调返回Date socket.on('request-date', (callback) => { callback(new Date()); }); });
客户端代码示例:
import { io } from 'socket.io-client'; // 客户端连接时同样配置parser const socket = io('http://your-server-url', { parser: { reviver: (key, value) => { if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value)) { return new Date(value); } return value; }, replacer: (key, value) => { if (value instanceof Date) { return value.toISOString(); } return value; } } }); // 接收时直接用Date类型 socket.on('current-time', (date) => { console.log(date instanceof Date); // 输出true console.log(date.getHours()); // 可以直接调用Date方法 }); // 发送Date给服务器,服务器端会自动转成Date类型 socket.emit('send-date-to-server', new Date());
注意:如果你的业务中有其他符合ISO日期格式的字符串(不是Date转的),正则可能会误判,这时候可以看方案3。
方案2:用时间戳传输(更轻量)
如果场景比较简单,也可以直接传输Date的时间戳(数字类型),接收时直接用new Date(timestamp)转换,体积比ISO字符串更小。
示例:
// 服务器发送 socket.emit('current-timestamp', new Date().getTime()); // 客户端接收 socket.on('current-timestamp', (timestamp) => { const date = new Date(timestamp); // 直接使用date }); // 客户端发送Date给服务器 socket.emit('send-date', new Date().getTime()); // 服务器接收 socket.on('send-date', (timestamp) => { const date = new Date(timestamp); });
这个方案优点是简单、性能好,缺点是可读性差,没法直接从传输的数据里看出日期。
方案3:自定义标记识别Date(更安全)
如果担心正则误判,可以给Date对象加一个自定义标记,比如包装成{ __type: 'Date', value: 'ISO字符串' },序列化和反序列化时识别这个标记,避免误转换。
服务器端parser配置:
parser: { reviver: (key, value) => { if (value && typeof value === 'object' && value.__type === 'Date') { return new Date(value.value); } return value; }, replacer: (key, value) => { if (value instanceof Date) { return { __type: 'Date', value: value.toISOString() }; } return value; } }
客户端配置和服务器端一样,这样只有被标记为__type: 'Date'的对象才会被转成Date类型,完全不会误判其他字符串或对象。
内容的提问来源于stack exchange,提问作者qwerty qwerty
相关产品推荐
相关产品推荐

