SpringBoot搭建的Websocket服务器老是掉线问题解决(Nginx代理)

前提

报错信息

java.io.EOFException: null
	at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1293) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
	at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1181) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
	at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:74) ~[tomcat-embed-websocket-10.1.28.jar:10.1.28]
	at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:184) ~[tomcat-embed-websocket-10.1.28.jar:10.1.28]
	at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:164) ~[tomcat-embed-websocket-10.1.28.jar:10.1.28]
	at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:152) ~[tomcat-embed-websocket-10.1.28.jar:10.1.28]
	at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:60) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:57) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:904) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.28.jar:10.1.28]
	at java.base/java.lang.Thread.run(Thread.java:840) ~[na:na]

pom.xml 文件 - 依赖版本

<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>6.1.12</spring.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.16</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-websocket</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-websocket</artifactId>
        <version>10.1.28</version>
    </dependency>
</dependencies>

解决方案

WebSocket 是长连接,默认的超时时间可能不够长,尤其是在连接空闲时,Nginx 会因超时关闭连接。

可以在 Nginx 配置中显式设置 proxy_read_timeoutproxy_connect_timeout,以增加 WebSocket 连接的容忍时间。

增加 proxy_send_timeout,这个配置可以帮助延长客户端发送数据到 Nginx 代理的超时时间。尽管 WebSocket 通常不会频繁发送数据,但添加这个设置可以确保连接稳定。

修改Nginx配置

原始配置

    location / {
        proxy_pass http://localhost:8081/websocket/message;  # 将请求转发到 WebSocket 服务的具体路径
        proxy_http_version 1.1;  # 使用 HTTP/1.1
        proxy_set_header Upgrade $http_upgrade;  # WebSocket 升级支持
        proxy_set_header Connection 'upgrade';  # WebSocket 升级支持
        proxy_set_header Host $host;  # 保留原始 Host 信息
        proxy_cache_bypass $http_upgrade;  # WebSocket 不使用缓存
    }

修改后

location / {
    proxy_pass http://localhost:8081/websocket/message;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;

    # 增加超时时间
    proxy_connect_timeout 60s;  # 设置连接超时(可根据需要调整)
    proxy_read_timeout 3600s;   # 设置读取超时,避免长时间不活动断开连接
    proxy_send_timeout 3600s;  # 设置发送超时
}

其他建议

调整 Nginx 的 worker_processesworker_connections

如果服务器上有大量的并发 WebSocket 连接,可能需要增加 Nginx 的 worker_processes worker_connections 设置,以提升处理并发连接的能力。

worker_processes  auto;  # 根据 CPU 核数自动设置
worker_connections  1024;  # 每个进程最多能处理的连接数,视你的服务器能力而定

增加 keepalive_timeout 设置:

如果WebSocket 连接在空闲时容易掉线,考虑增加 keepalive_timeout 设置,确保 Nginx 和客户端保持连接。

keepalive_timeout  65;  # 这个值可以根据需要调整,单位为秒
### 使用 Spring Boot 构建 WebSocket 服务器 为了使用 Spring Boot 创建 WebSocket 服务器,需遵循特定配置流程并编写相应代码。 #### 添加 Maven 依赖项 首先,在 `pom.xml` 文件中加入 WebSocket 支持所需的依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 此操作确保项目具备必要的库来处理 WebSocket 连接[^3]。 #### 配置 WebSocket 消息代理 接着定义消息代理类用于管理会话和路由消息。通过继承 `WebSocketMessageBrokerConfigurer` 接口可自定义设置: ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws").withSockJS(); } } ``` 上述代码片段启用了简单的内存内消息代理,并指定了应用程序前缀 `/app` 和广播主题路径 `/topic`;还注册了一个 SockJS 终端节点 `/ws` 来兼容不同浏览器环境下的 WebSocket 协议[^1]。 #### 编写控制器逻辑 随后创建处理器类监听来自客户端的消息请求,并向订阅者发送响应数据: ```java @Controller public class GreetingController { @MessageMapping("/hello") @SendTo("/topic/greetings") public String greeting(String message) throws Exception { Thread.sleep(1000); // simulated delay return "Hello, " + HtmlUtils.htmlEscape(message); } } ``` 这里展示了当收到发往 `/app/hello` 的 STOMP 命令时触发问候语句生成的过程,之后将结果推送给所有已订阅 `/topic/greetings` 主题的用户[^2]。 #### 测试 WebSocket 功能 最后一步是在前端页面建立与后端的服务连接测试交互效果。可以利用 JavaScript 或其他框架完成这一部分的工作。确认一切正常运作后即成功实现了基于 Spring Boot 平台上的 WebSocket 应用程序开发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值