1. 引言
在现代 Web 应用中,WebSocket 以其全双工通信、低延迟、减少 HTTP 开销等优势,被广泛应用于即时通讯、在线游戏、实时数据推送等场景。然而,在涉及用户认证时,WebSocket 存在一个常见问题——每次刷新页面都会重新建立 WebSocket 连接,导致用户需要重新认证。
1.1 WebSocket 连接与用户认证的挑战
WebSocket 连接是长连接,与传统 HTTP 请求不同,它并不会在每次通信时都自动携带身份认证信息(如 Cookie、Session)。这意味着:
- 页面刷新后,WebSocket 连接会断开并重新建立,服务器无法自动识别用户身份,必须重新进行认证。
- 传统的 WebSocket 认证流程较长,通常是:
- 前端建立 WebSocket 连接;
- 连接成功后,前端发送 Token 进行身份验证;
- 服务器验证 Token,返回认证结果。
这样下来,整个认证过程涉及三次数据往返(RTT,Round Trip Time),不仅增加了服务器压力,还会影响用户体验,尤其是在网络延迟较高的环境下,认证速度会明显变慢。
1.2 目标:减少认证回合,提高用户体验
为了解决这个问题,我们希望优化 WebSocket 认证流程,目标是:
- 减少认证数据往返次数,从三次缩减为两次甚至一次;
- 在 WebSocket 连接建立时就完成认证,避免额外的认证消息交互;
- 确保认证方式安全可靠,防止 Token 泄露或被劫持。
通过对 WebSocket 连接建立过程的深入研究,我们发现可以在WebSocket 握手阶段(仍然是 HTTP 请求)直接传递 Token,从而让服务器在握手时就完成身份认证。这样可以大大减少通信回合,提高用户体验。
2. WebSocket 认证优化思路
为了减少 WebSocket 认证的额外开销,我们需要优化传统的认证流程,让用户在刷新页面时不需要额外发送认证请求,而是在 WebSocket 连接建立的同时完成认证。本节将详细介绍 WebSocket 认证的优化方向,并对比不同方案的优缺点。
2.1 传统 WebSocket 认证方式及其问题
在标准的 WebSocket 连接流程中,前端通常按照以下方式进行身份认证:
- 建立 WebSocket 连接(
new WebSocket(url)
)。 - WebSocket 连接建立后,前端发送 Token(
ws.send(token)
)。 - 服务器接收 Token 并进行身份验证。
- 服务器返回认证结果,前端决定是否继续通信。
这种方式的主要问题是:
- 增加了不必要的通信回合。连接建立后,还需要额外的消息往返进行身份认证,导致三次通信(RTT3)。
- 影响用户体验。网络延迟高时,用户可能需要等待较长时间才能完成认证,体验不够流畅。
- 安全性问题。Token 通过 WebSocket 发送,可能被恶意中间人劫持,存在一定的安全风险(虽然 WebSocket 连接一般是
wss://
加密的,但仍需谨慎)。
2.2 目标:让 WebSocket 认证更高效
为了优化 WebSocket 认证,我们希望达到以下目标:
- 减少通信回合,最好在 WebSocket 连接建立的同时完成认证,避免额外的认证数据交互。
- 不依赖额外的 WebSocket 消息 进行认证,而是在 握手阶段(WebSocket Upgrade 请求) 直接完成 Token 认证。
- 兼容性强,安全性高,避免 Token 通过 WebSocket 发送,减少被劫持的风险。
基于以上目标,我们提出两种优化方案:
2.3 方案一:通过 URL 传递 Token(推荐方案)
实现思路:
在 WebSocket 连接 URL 中直接拼接 Token,例如:
java">const ws = new WebSocket("wss://example.com/ws?token=your_token_here");
服务器在 Netty 中解析 WebSocket 握手请求的 URL,提取 Token 进行身份认证,认证成功后绑定 Token 到用户的 WebSocket 会话中。
优点:
✅ 减少一次往返,从 RTT3 降低为 RTT2(握手 + 服务器返回认证结果)。
✅ 无需额外 WebSocket 消息 进行认证,认证逻辑清晰。
✅ 易于实现,只需在 WebSocket 握手阶段解析 URL 参数即可。
注意事项:
⚠ 安全性问题:
- 避免 Token 长期存留在 URL 记录(如浏览器历史、服务器日志等)。
- 可以在服务器解析 Token 后立即从 URL 中删除,避免 Token 泄露。
2.4 方案二:利用 HTTP 头传递 Token(更安全但兼容性稍差)
实现思路:
WebSocket 的初始握手是基于 HTTP 进行的,因此可以利用 HTTP 头部(Authorization) 传递 Token,例如:
java">const ws = new WebSocket("wss://example.com/ws", [], {headers: { Authorization: "Bearer your_token_here" }
});
然后,在 Netty 服务器中解析 Authorization
头,提取 Token 进行身份认证。
优点:
✅ 安全性更高,Token 不会出现在 URL 中,避免泄露风险。
✅ 减少 WebSocket 消息认证,直接在握手时完成身份校验。
缺点:
⚠ 前端受限:浏览器原生 WebSocket
API 不支持自定义 HTTP 头,必须通过 自定义 WebSocket 客户端(如 Node.js 或 JavaScript WebSocket 库)实现。
⚠ 兼容性问题:部分 WebSocket 服务器和代理可能不会转发自定义 HTTP 头,需要额外配置。
2.5 方案三(失败方案):利用 WebSocket protocols
传递 Token
WebSocket 连接时支持 protocols
参数,原本希望使用它来传递 Token,例如:
java">const ws = new WebSocket("wss://example.com/ws", ["token_your_token_here"]);
然而,WebSocket protocols
的作用是指定子协议(如 graphql-ws
),并不是设计来传递 Token,因此 服务器端 Netty 解析 protocols
时无法正确获取 Token。
最终结论: 该方案不可行,不推荐使用。
2.6 方案对比与最终选择
方案 | 传递方式 | 兼容性 | 安全性 | 优势 | 适用场景 |
---|---|---|---|---|---|
URL 拼接 Token | URL 参数 | ✅ 浏览器支持 | ⚠ 需要删除 Token | 🚀 简单易用,减少一次通信 | 推荐,适合大多数情况 |
HTTP 头部 Token | Authorization 头 | ❌ 需自定义客户端 | ✅ 安全性高 | 🚀 服务器端认证直接完成 | 适合服务器或非浏览器环境 |
WebSocket protocols | protocols | ❌ 不支持 | ❌ 不安全 | ❌ 无法正确传递 Token | 失败方案,不推荐 |
综合来看,"URL 拼接 Token" 是最简单、最易用、且兼容性最好的方案,因此推荐作为主要优化方式。
2.7 结论与下一步
通过在 WebSocket 连接握手阶段 直接传递 Token,我们可以有效减少不必要的认证回合,优化用户体验。在接下来的章节,我们将深入讲解如何在 Netty 服务器端 解析 Token 并完成身份认证,确保 WebSocket 认证的安全性和稳定性。
3. WebSocket 握手阶段传递 Token 的技术实现
在上一节中,我们确定了在 WebSocket 连接握手阶段传递 Token 是优化 WebSocket 认证的最佳方案。本节将详细讲解如何在前端传递 Token,以及如何在 Netty 服务器端解析和验证 Token,确保 WebSocket 连接的安全性和高效性。
3.1 前端如何在 WebSocket 握手时传递 Token
方案一:通过 URL 传递 Token(推荐)
在 WebSocket 连接 URL 中直接拼接 Token,例如:
java">const token = "your_token_here"; // 这个 Token 一般从 localStorage 或 cookies 获取
const ws = new WebSocket(`wss://example.com/ws?token=${encodeURIComponent(token)}`);
📌 注意事项:
encodeURIComponent(token)
作用是对 Token 进行 URL 编码,避免特殊字符影响 URL 解析。- 不要让 Token 长时间存留在 URL 记录中,服务器端拿到 Token 后要尽快清理,防止 Token 泄露。
方案二:使用 HTTP 头传递 Token(仅适用于非浏览器环境)
如果 WebSocket 连接是由 Node.js 或其他后端服务 发起的,可以使用 HTTP 头传递 Token,例如:
java">const WebSocket = require('ws');const ws = new WebSocket("wss://example.com/ws", {headers: {Authorization: `Bearer your_token_here`}
});
📌 注意事项:
- 这种方式 浏览器原生 WebSocket API 不支持,适用于后端对后端(Server-to-Server)WebSocket 连接。
- 服务器端需要在 HTTP 头中提取
Authorization
并解析 Token。
3.2 Netty 服务器端如何解析 Token
无论 Token 是通过 URL 传递 还是 HTTP 头传递,Netty 服务器端的逻辑主要分为三步:
- 在 WebSocket 握手阶段拦截 HTTP 请求。
- 提取 Token 并进行身份认证。
- 认证成功后,将 Token 绑定到 WebSocket 连接(Channel),用于后续通信。
3.2.1 Netty 服务器端代码实现
(1)自定义 WebSocket 握手处理器
我们需要在 WebSocket 握手阶段解析 Token,并存储到 Channel 的 Attributes
中,方便后续使用。
java">import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;
import java.util.List;
import java.util.Map;public class WebSocketHandshakeHandler extends SimpleChannelInboundHandler<FullHttpRequest> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) {// 解析 TokenString token = extractToken(req);if (token == null || !isValidToken(token)) {// 认证失败,关闭连接ctx.close();return;}// 认证成功,将 Token 绑定到 Channelctx.channel().attr(AttributeKey.valueOf("token")).set(token);// 继续处理 WebSocket 握手ctx.fireChannelRead(req.retain());}// 解析 URL 中的 Tokenprivate String extractToken(FullHttpRequest req) {QueryStringDecoder decoder = new QueryStringDecoder(req.uri());Map<String, List<String>> params = decoder.parameters();if (params.containsKey("token")) {return params.get("token").get(0);}return null;}// 这里可以调用自己的 Token 认证逻辑,例如 JWT 解析private boolean isValidToken(String token) {return "your_token_here".equals(token); // 这里替换成实际的 Token 验证逻辑}
}
📌 代码解读:
channelRead0()
方法会在 WebSocket 握手阶段拦截 HTTP 请求。extractToken(req)
方法用于从 URL 解析 Token。isValidToken(token)
方法用于验证 Token 的有效性(这里可以换成 JWT 解析)。ctx.channel().attr(AttributeKey.valueOf("token")).set(token);
用于将 Token 绑定到 Channel,方便后续使用。
(2)WebSocket 握手完成后,继续处理 WebSocket 消息
WebSocket 握手完成后,我们需要创建 WebSocket 处理器,确保后续通信时能够获取用户身份。
java">import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;public class WebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {// 读取用户 Token(之前存储在 Channel 的 Attribute 中)String token = (String) ctx.channel().attr(AttributeKey.valueOf("token")).get();if (token == null) {ctx.close();return;}// 处理 WebSocket 消息System.out.println("Received message: " + msg.text());ctx.writeAndFlush(new TextWebSocketFrame("Server received your message: " + msg.text()));}
}
📌 代码解读:
ctx.channel().attr(AttributeKey.valueOf("token")).get();
读取 WebSocket 握手阶段存储的 Token。- 如果 Token 为空,说明认证失败,关闭连接。
- 认证成功后,继续处理 WebSocket 消息。
3.3 Netty 服务器端完整 Pipeline 组装
在 Netty 服务器启动时,我们需要正确组装 WebSocket 握手处理器和消息处理器。
java">import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) {ch.pipeline().addLast(new HttpServerCodec()); // HTTP 解析ch.pipeline().addLast(new HttpObjectAggregator(65536)); // 处理完整 HTTP 请求ch.pipeline().addLast(new WebSocketHandshakeHandler()); // 解析 Token 并认证ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws")); // WebSocket 握手ch.pipeline().addLast(new WebSocketFrameHandler()); // 处理 WebSocket 消息}
}
📌 代码解读:
HttpServerCodec
处理 HTTP 请求和响应。HttpObjectAggregator
处理 HTTP 完整请求(包括 WebSocket 握手)。WebSocketHandshakeHandler
解析 Token 并进行认证。WebSocketServerProtocolHandler("/ws")
处理 WebSocket 协议升级。WebSocketFrameHandler
处理 WebSocket 消息传输。
4. Netty 服务器端 WebSocket 认证优化
在上一节中,我们实现了 WebSocket 握手阶段的 Token 传递和验证,确保 WebSocket 连接在建立时完成身份认证。然而,现有方案仍然存在优化空间,包括:
- Token 认证逻辑的优化:减少重复解析 Token,提高认证效率。
- Token 续期机制:当 Token 即将过期时,支持在线续期,避免用户被强制下线。
- 多端登录管理:确保同一账号可以安全地在多个设备登录,或限制单设备登录。
- 权限控制优化:不同用户类型可访问不同的 WebSocket 通道,提高安全性和可维护性。
本节将针对这些优化点,详细讲解 Netty 服务器端的优化方案和实现方法。
4.1 Token 认证逻辑优化
🔹 问题:每次握手都要解析 Token,导致性能损耗
在当前实现中,每次 WebSocket 握手时,服务器都需要解析并验证 Token。如果 Token 解析逻辑复杂(如 JWT 解析、数据库查询等),可能会影响服务器性能。
✅ 解决方案:引入缓存,加速 Token 解析
可以使用 本地缓存(如 Caffeine)或分布式缓存(如 Redis),存储已验证的 Token,避免重复解析。例如:
java">import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;import java.util.concurrent.TimeUnit;public class TokenCache {// 使用 Caffeine 作为本地缓存,Token 过期时间设为 10 分钟private static final Cache<String, Boolean> tokenCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).maximumSize(10_000).build();// 校验 Tokenpublic static boolean isValidToken(String token) {// 先查缓存Boolean isValid = tokenCache.getIfPresent(token);if (isValid != null) {return isValid;}// 若缓存中不存在,则进行 Token 解析(可以是 JWT 解析、数据库查询等)boolean valid = verifyTokenFromDatabaseOrJWT(token);// 缓存结果,避免重复解析tokenCache.put(token, valid);return valid;}// 这里模拟一个 Token 验证逻辑private static boolean verifyTokenFromDatabaseOrJWT(String token) {return "valid_token".equals(token); // 实际上应调用数据库或 JWT 解析库}
}
📌 优化效果:
- 第一次验证 Token 仍然执行完整的解析逻辑。
- 之后的请求将直接从缓存读取,减少计算量,提高认证效率。
- 10 分钟后 Token 过期,防止长期缓存导致安全隐患。
4.2 Token 续期机制
🔹 问题:Token 过期后,WebSocket 连接被强制断开,用户体验差
如果 Token 有效期较短,用户需要频繁重新连接 WebSocket,影响体验。
✅ 解决方案:支持 Token 续期
可以在 WebSocket 连接中定期检查 Token 是否即将过期,并在即将过期时让客户端自动更新 Token,避免断开连接。例如:
1️⃣ 服务器端实现 Token 续期检测
java">import io.netty.channel.Channel;
import io.netty.util.AttributeKey;import java.util.concurrent.ConcurrentHashMap;public class TokenManager {private static final ConcurrentHashMap<Channel, String> channelTokenMap = new ConcurrentHashMap<>();// 绑定 Token 到 Channelpublic static void bindToken(Channel channel, String token) {channel.attr(AttributeKey.valueOf("token")).set(token);channelTokenMap.put(channel, token);}// 检查 Token 是否即将过期public static boolean isTokenExpiringSoon(String token) {return token.equals("expiring_token"); // 模拟 Token 过期检查}// 更新 Tokenpublic static void refreshToken(Channel channel, String newToken) {channel.attr(AttributeKey.valueOf("token")).set(newToken);channelTokenMap.put(channel, newToken);}
}
2️⃣ 客户端定期检查 Token 过期,并更新 Token
java">function checkTokenExpiry() {setInterval(() => {fetch('/api/check-token') // 询问服务器 Token 是否即将过期.then(response => response.json()).then(data => {if (data.expiring) {refreshToken(); // 如果快过期了,就刷新 Token}});}, 30000); // 每 30 秒检查一次
}function refreshToken() {fetch('/api/refresh-token').then(response => response.json()).then(data => {ws.close(); // 关闭当前 WebSocket 连接ws = new WebSocket(`wss://example.com/ws?token=${encodeURIComponent(data.newToken)}`);});
}
📌 优化效果:
- 避免 Token 过期导致 WebSocket 断开,提升用户体验。
- 仅在 Token 需要续期时进行刷新,减少不必要的 Token 解析操作。
4.3 多端登录管理
🔹 问题:同一账号可能在多个设备登录,导致 Token 被滥用
例如,用户在 PC 和手机同时使用 WebSocket,可能导致 Token 重复使用,带来安全风险。
✅ 解决方案:限制同一账号的 WebSocket 连接数量
可以使用 Redis 记录当前在线的 Token,如果发现同一账号的 Token 在多个设备登录,则主动踢掉旧连接。
Netty 服务器端实现
java">import java.util.concurrent.ConcurrentHashMap;
import io.netty.channel.Channel;public class WebSocketSessionManager {private static final ConcurrentHashMap<String, Channel> userSessions = new ConcurrentHashMap<>();public static void bindUser(String userId, Channel channel) {if (userSessions.containsKey(userId)) {// 踢掉之前的连接userSessions.get(userId).close();}userSessions.put(userId, channel);}public static void removeUser(String userId) {userSessions.remove(userId);}
}
📌 优化效果:
- 防止 Token 被盗用,限制同时在线的 WebSocket 连接数量。
- 确保 WebSocket 连接始终是最新的,避免同一用户在多个设备上造成数据不一致。
4.4 权限控制优化
🔹 问题:不同用户类型需要访问不同的 WebSocket 通道
例如:
- 普通用户只能订阅
public_chat
频道。 - 管理员可以订阅
admin_dashboard
频道。
✅ 解决方案:基于角色的 WebSocket 频道管理
在服务器端,解析 Token 后,将 用户角色信息绑定到 Channel,限制用户访问的 WebSocket 频道。
java">public class WebSocketAuthHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {String role = ctx.channel().attr(AttributeKey.valueOf("role")).get().toString();if (!"admin".equals(role) && msg.text().contains("admin_dashboard")) {ctx.writeAndFlush(new TextWebSocketFrame("Permission denied"));return;}ctx.fireChannelRead(msg.retain());}
}
📌 优化效果:
- 基于 Token 角色限制 WebSocket 频道访问,提高安全性。
- 确保不同用户类型只能访问自己的数据,防止权限泄露。
总结
本节优化了 WebSocket 认证,包括:
✔ 缓存 Token 提高认证效率
✔ 支持 Token 续期,避免连接断开
✔ 限制多端登录,提升安全性
✔ 基于角色的权限管理
5. 认证通过后的用户信息推送与刷新
在 WebSocket 认证成功后,用户的身份信息已经确定,此时可以进行用户信息的推送和刷新。这一环节主要涉及:
- 用户连接后,主动推送用户的最新信息,确保前端拿到最新状态。
- 用户信息发生变化(如昵称、头像、权限等)时,自动推送更新,避免前端数据滞后。
- 支持前端主动请求刷新用户信息,保证客户端在需要时能够获取最新数据。
下面,我们逐步分析如何在 Netty 服务器端 实现这些功能。
5.1 用户连接后主动推送信息
🔹 问题:用户 WebSocket 连接成功后,前端需要获取最新用户信息
当 WebSocket 连接建立后,前端可能需要:
- 获取用户的基本信息(如用户名、头像、权限等)。
- 获取用户的未读消息数量。
- 获取其他应用状态数据(如好友在线状态、系统通知等)。
✅ 解决方案:在 WebSocket 握手成功后,服务器主动推送用户信息
我们可以在 WebSocket 握手完成时,从数据库或缓存中读取用户信息,并主动推送给前端。
Netty 服务器端实现
java">import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import com.fasterxml.jackson.databind.ObjectMapper;public class UserInfoPushHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {private static final ObjectMapper objectMapper = new ObjectMapper();@Overridepublic void channelActive(ChannelHandlerContext ctx) {Channel channel = ctx.channel();String userId = channel.attr(AttributeKey.valueOf("userId")).get().toString();// 查询用户信息UserInfo userInfo = getUserInfoFromDatabase(userId);// 发送用户信息到前端try {String userInfoJson = objectMapper.writeValueAsString(userInfo);channel.writeAndFlush(new TextWebSocketFrame(userInfoJson));} catch (Exception e) {e.printStackTrace();}}private UserInfo getUserInfoFromDatabase(String userId) {// 这里应该是数据库查询或缓存获取return new UserInfo(userId, "张三", "/avatar.png", "admin");}
}
📌 优化效果:
- 用户连接后立即获取最新信息,无需前端主动请求。
- 避免前端页面出现数据缺失或延迟加载的问题。
5.2 用户信息变化时自动推送更新
🔹 问题:如果用户信息在其他地方修改了,WebSocket 连接的前端不会自动更新
例如:
- 用户修改了头像或昵称,前端不会自动更新。
- 管理员修改了用户权限,但 WebSocket 连接中的用户权限仍然是旧的。
✅ 解决方案:服务器监听用户信息变更,主动通知所有在线 WebSocket 客户端
可以使用 消息队列(如 Redis Pub/Sub、Kafka)或事件驱动机制,当用户信息更新时,通知 WebSocket 服务器推送消息。
1️⃣ 监听用户信息变更事件
java">import java.util.concurrent.ConcurrentHashMap;
import io.netty.channel.Channel;public class UserSessionManager {private static final ConcurrentHashMap<String, Channel> userChannelMap = new ConcurrentHashMap<>();public static void bindUser(String userId, Channel channel) {userChannelMap.put(userId, channel);}public static void unbindUser(String userId) {userChannelMap.remove(userId);}// 当用户信息更新时,推送最新数据public static void pushUserInfoUpdate(String userId, UserInfo newUserInfo) {Channel channel = userChannelMap.get(userId);if (channel != null && channel.isActive()) {try {String json = new ObjectMapper().writeValueAsString(newUserInfo);channel.writeAndFlush(new TextWebSocketFrame(json));} catch (Exception e) {e.printStackTrace();}}}
}
2️⃣ 用户信息修改时触发推送
public class UserService {public void updateUserInfo(String userId, String newNickname, String newAvatar) {// 更新数据库中的用户信息UserInfo updatedUser = updateUserInDatabase(userId, newNickname, newAvatar);// 触发 WebSocket 推送UserSessionManager.pushUserInfoUpdate(userId, updatedUser);}private UserInfo updateUserInDatabase(String userId, String nickname, String avatar) {return new UserInfo(userId, nickname, avatar, "admin"); // 模拟数据库更新}
}
📌 优化效果:
- 当用户信息变更时,WebSocket 服务器自动推送最新信息,确保前端数据一致。
- 无需前端轮询,大幅降低服务器负载。
5.3 前端主动请求刷新用户信息
🔹 问题:某些情况下,前端可能需要主动刷新用户信息
例如:
- 用户希望手动刷新个人资料。
- WebSocket 连接异常后重新同步数据。
- 用户切换页面后,希望重新获取最新数据。
✅ 解决方案:前端发送请求,服务器返回最新的用户信息
我们可以在 WebSocket 服务器端监听 "refreshUserInfo" 事件,当收到该消息时,返回最新的用户信息。
Netty 服务器端处理用户刷新请求
java">public class UserInfoRefreshHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {if ("refreshUserInfo".equals(msg.text())) {String userId = ctx.channel().attr(AttributeKey.valueOf("userId")).get().toString();UserInfo userInfo = getUserInfoFromDatabase(userId);try {String json = new ObjectMapper().writeValueAsString(userInfo);ctx.channel().writeAndFlush(new TextWebSocketFrame(json));} catch (Exception e) {e.printStackTrace();}} else {ctx.fireChannelRead(msg.retain());}}
}
前端请求刷新用户信息
java">// 发送刷新请求
function requestUserInfoRefresh() {ws.send("refreshUserInfo");
}// 监听 WebSocket 返回的新用户信息
ws.onmessage = function(event) {const userInfo = JSON.parse(event.data);console.log("用户信息更新:", userInfo);
};
📌 优化效果:
- 前端可以在任意时间主动请求最新用户信息,提升灵活性。
- 服务器只在必要时返回数据,减少不必要的推送,提高效率。
总结
本节介绍了 WebSocket 认证通过后,如何推送和刷新用户信息,主要优化点包括:
✔ WebSocket 连接建立后,服务器主动推送用户最新信息,避免前端等待。
✔ 当用户信息发生变更时,服务器自动推送更新,确保数据一致。
✔ 前端可以主动请求刷新用户信息,避免数据滞后。