问题中的关键在于 WebSocket 连接与 HTTP 连接之间的差异。当你使用 WebSocket API (new WebSocket(...)
) 连接到服务器时,你实际上正在建立一个持久的双向连接,不同于传统的 HTTP 连接。这意味着 WebSocket 连接并不遵循标准的 HTTP 响应代码(如 401)。
WebSocket 连接一旦建立,服务器不能通过发送 HTTP 响应代码来关闭连接。因此,在你的代码中,尽管你发送了一个 401 响应并关闭了连接,浏览器可能并没有正确地识别这个响应,因为它不符合 WebSocket 的协议。
如果你想在 WebSocket 连接中处理身份验证,你应该在你的应用程序协议中定义一种方式来传达身份验证失败。这通常意味着在 WebSocket 连接建立后,你需要定义一种消息格式,让服务器能够发送一个特殊的消息,告知客户端身份验证失败,然后客户端可以据此关闭连接。
例如,你可以在 WebSocket 握手成功后,发送一个包含身份验证信息的消息给服务器。如果服务器验证失败,它可以发送一个特定的消息(如一个包含错误码的消息)给客户端,然后客户端可以根据这个消息来关闭 WebSocket 连接。
以下是一个简单的例子:
服务器端:
// 假设你有一个处理 WebSocket 消息的方法
public void handleWebSocketMessage(ChannelHandlerContext ctx, TextWebSocketFrame frame) {
String message = frame.text();
// 解析消息并验证 token
if (!validateToken(message)) {
// 发送一个表示身份验证失败的消息
ctx.writeAndFlush(new TextWebSocketFrame("ERROR: 401 Unauthorized"));
ctx.close();
} else {
// 处理正常消息
}
}
客户端:
var socket = new WebSocket("ws://127.0.0.1:18080/ws?token=xxxx");
socket.onmessage = function(event) {
var message = event.data;
if (message.startsWith("ERROR:")) {
// 解析错误消息并处理
var errorCode = message.split(":")[1];
if (errorCode === "401") {
console.log("WebSocket connection closed due to unauthorized access.");
socket.close();
}
} else {
// 处理正常消息
}
};
这样,当服务器发送一个表示身份验证失败的消息时,客户端就可以捕获到这个消息,并据此关闭 WebSocket 连接。