Spring Boot WebSocket测试遇EOFException:请求头解析错误排查
解决Spring Boot WebSocket ServerEndpoint的HTTP请求头解析EOFException问题
我之前排查过类似的问题,你遇到的这个EOFException虽然常被归因为URL过长,但从你的场景来看明显不是这个原因。先把你碰到的异常日志贴出来方便参考:
2018-01-26 04:27:02 [http-nio-8090-exec-5] DEBUG o.a.coyote.http11.Http11Processor - Error parsing HTTP request header java.io.EOFException: null at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1250) at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1190) at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:717) at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:366) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:687) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748)
结合你的Spring Boot版本(内嵌Tomcat 8.5.23)和WebSocket配置代码,我判断大概率是WebSocket实现方式与配置不匹配导致的连接异常中断,进而触发了这个EOF异常。下面分两种情况给出解决方案:
情况1:你的ExchangeService是Spring WebSocketHandler的实现类
如果ExchangeService是继承自TextWebSocketHandler或AbstractWebSocketHandler的Spring风格处理器,那你的配置方向是对的,但可以补充两个优化点:
- 首先确保
ExchangeService类上没有标注JSR-356的@ServerEndpoint注解,避免两种模型冲突; - 在注册处理器时添加跨域允许配置(Chrome测试时可能因跨域限制导致连接中断):
@Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Autowired private ApplicationContext context; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(context.getBean(ExchangeService.class), "/ExchangeService") .setAllowedOrigins("*"); // 添加跨域允许 } }
情况2:你的ExchangeService使用了JSR-356的@ServerEndpoint注解
如果你的ExchangeService是用标准@ServerEndpoint注解实现的WebSocket端点,那当前的WebSocketConfigurer配置完全不匹配,需要改成注册ServerEndpointExporter来托管标准端点:
- 修改WebSocket配置类:
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(); } }
- 在
ExchangeService上添加@ServerEndpoint和@Component注解(让Spring管理实例):
import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import org.springframework.stereotype.Component; @ServerEndpoint("/ExchangeService") @Component public class ExchangeService { @OnOpen public void onOpen(Session session) { // 连接打开逻辑 } @OnMessage public void onMessage(String message, Session session) { // 消息处理逻辑 } }
其他排查方向
如果上面的方案没解决问题,可以试试这些小技巧:
- 调整Tomcat的缓冲区配置,在
application.properties中添加:
server.tomcat.max-http-header-size=8192 server.tomcat.socket.buffer-size=8192
- 检查Chrome控制台的WebSocket连接代码是否正确,比如:
const ws = new WebSocket('ws://localhost:8090/ExchangeService'); ws.onopen = () => console.log('连接成功'); ws.onerror = err => console.error('连接错误:', err);
看看控制台有没有额外的错误提示。
内容的提问来源于stack exchange,提问作者mohit kumar




