项目中的websocket突然连不上了,检查后台发现报的这个错误 No 'jakarta.websocket.server.ServerContainer' ServletContext attribute. Are you running in a Servlet container that supports JSR-356 ,经过排查终于找到原因,在此记录下
问题复现
1. 版本
spring-boot-starter-websocket 3.2.0
dynamic-datasource-spring-boot3-starter: 4.2.0
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>4.2.0</version>
</dependency>
2. websocket相关代码
package org.example.config;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
@Configuration
@EnableWebSocket
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry
.addHandler(new AbstractWebSocketHandler() {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("连接成功" + session.getId());
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
System.out.printf("收到%s消息%s%n", session.getId(), message.getPayload());
session.sendMessage(message);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("连接断开" + session.getId());
}
}, "/wsb")
.setAllowedOrigins("*");
}
}
3. 使用postman工具进行测试,发现连不上,报的500错误
报错信息如下
2024-03-20T09:47:41.877+08:00 ERROR 10176 --- [io-10090-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.web.socket.server.HandshakeFailureException: Uncaught failure for request http://localhost:10090/wsb - No 'jakarta.websocket.server.ServerContainer' ServletContext attribute. Are you running in a Servlet container that supports JSR-356?] with root cause
java.lang.IllegalArgumentException: No 'jakarta.websocket.server.ServerContainer' ServletContext attribute. Are you running in a Servlet container that supports JSR-356?
寻找原因
从报错信息来看好像是容器不支持 jsr-356(jsr-356应该是websocket的意思),从启动信息来看用的容器是tomcat 10.1.6,这个是肯定支持websocket的,所以不是这个问题
查看其它依赖有没有引入其它容器,发现dynamic-datasource-spring-boot3-starter竟然引了undertow的依赖,可能是一个项目同时引了tomcat和undertow的starter导致了这个问题
排除undertow的依赖重启服务,再次测试,websocket可以正常连接和使用
解决方法
1. 排除dynamic-datasource-spring-boot3-starter中的undertow依赖
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</exclusion>
</exclusions>
2. 查了一下其它版本的依赖,发现好像只有4.2.0版本有undertow的依赖,所以使用dynamic-datasource-spring-boot3-starter其它依赖版本也可以,如4.3.0