You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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是继承自TextWebSocketHandlerAbstractWebSocketHandler的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来托管标准端点:

  1. 修改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();
    }
}
  1. 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

火山引擎 最新活动