You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非HTTPS环境SpringBoot实现WebSocket连接404异常问题

问题根因说明

你遇到的两个报错原因非常明确:

  • ws://连接返回404:是因为SpringBoot内嵌Tomcat默认不会扫描@ServerEndpoint注解,你写的WebSocket端点根本没被注册到服务里,访问自然找不到路径
  • wss://连接报方法名非法字符:是因为你本地运行的是普通HTTP服务,没有配置SSL证书,wss是加密WebSocket协议,对应HTTPS端口,你拿wss连HTTP端口时,Tomcat把TLS握手的二进制数据包当成普通HTTP请求解析,必然抛出这个异常,本地测试直接用ws即可,等后续部署HTTPS时再配置wss。
排查解决步骤

1. 补全SpringBoot WebSocket核心配置

在SpringBoot能扫描到的包路径下(和启动类同层级/子层级的config包下)新增配置类,注册ServerEndpoint扫描器:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

注意:如果后续你把项目打war包部署到外部Tomcat,这个Bean可以去掉,外部Tomcat会自动扫描@ServerEndpoint注解,但本地用内嵌Tomcat测试必须加这个配置,否则端点不会生效。

2. 检查路径拦截与上下文配置

  • 如果你项目用了SpringSecurity、自定义Filter/Interceptor,必须把/events/**路径加到放行规则里,WebSocket第一次握手是HTTP升级请求,被拦截器拦截会直接导致连接失败
  • 检查application.yml/application.properties里有没有配置server.servlet.context-path,如果配置了比如/api作为上下文路径,前端连接地址要对应改成ws://localhost:8080/api/events/1,漏写上下文路径也会报404。

3. 处理跨域问题

如果你的前端页面是跑在其他端口(比如本地前端调试用3000/5500端口),需要给WebSocket端点加跨域允许配置,修改@ServerEndpoint注解,新增跨域配置器:

@ServerEndpoint(
        value="/events/{boardid}",
        decoders = MessageDecoder.class,
        encoders = MessageEncoder.class,
        configurator = WebSocketCorsConfig.class
)

新增跨域配置类:

import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import java.util.Collections;

public class WebSocketCorsConfig extends ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        // 本地测试允许所有跨域,生产环境替换为实际业务域名即可
        response.getHeaders().put("Access-Control-Allow-Origin", Collections.singletonList("*"));
        super.modifyHandshake(sec, request, response);
    }
}

4. 检查编解码器实现

确认你自定义的MessageDecoder、MessageEncoder符合规范:

  • 解码器实现Decoder.Text<Message>接口,重写decode方法,能正确将收到的字符串转为Message对象
  • 编码器实现Encoder.Text<Message>接口,重写encode方法,能正确将Message对象转为可传输的字符串
  • 两个类都必须是public修饰,提供public无参构造方法,否则端点初始化会失败。
现有代码bug修复

你贴的业务代码里有两个小问题,顺手修了避免后续出问题:

  1. @OnMessage方法里没有把前端传来的消息内容设置到广播的Message对象里,现在广播的是空消息,客户端收不到实际发送的内容,修改为:
@OnMessage
public void onMessage(Session session, String message) throws IOException, EncodeException {
    Message msg = new Message();
    msg.setFrom(users.get(session.getId()));
    msg.setContent(message); // 补全消息内容赋值
    broadcast(msg);
    System.out.println("["+session.getId()+"]: "+message);
}
  1. @OnClose方法里没有清理users里的会话映射,长时间运行会内存泄漏,同时日志打印内容缺失,修改为:
@OnClose
public void onClose(Session session) throws IOException, EncodeException {
    socketEndpoint.remove(this);
    String boardid = users.remove(session.getId()); // 移除失效的用户映射,避免内存泄漏
    Message message = new Message();
    message.setFrom(boardid);
    message.setContent("Disconnected!");
    broadcast(message);
    System.out.println("Connection closed with: "+session.getId());
}
排查优先级建议
  • 第一步先加ServerEndpointExporter配置类,重启服务后测试ws连接,90%的概率404问题会直接解决
  • 如果还是404,再检查拦截器放通、上下文路径配置
  • 能连通但收不到消息时,再检查编解码器和上面提到的消息赋值问题
  • wss相关的问题本地不用处理,等后续部署HTTPS环境时,给服务配置SSL证书,前端把连接地址换成wss即可。

内容的提问来源于stack exchange,提问作者Tyris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 07:42:18