autorenew

Fixing WebSocket Auto-Disconnect with java.io.EOFException

1. Problem

After using Nginx reverse proxy for the WebSocket service, it automatically disconnects. The log shows:

2024-02-22 18:51:05:964 1901020240223104709130 [ERROR] websocket connection error,
java.io.EOFException: null
        at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1339)
        at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1226)
        at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:75)
        at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:183)
        at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:162)
        at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:157)
        at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:60)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:59)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.base/java.lang.Thread.run(Thread.java:842)

2. Cause

When using Nginx reverse proxy, connections without data transmission for more than 60 seconds will automatically disconnect.

3. Solutions

1. Modify Nginx Configuration

proxy_read_timeout 3600;

Increase the timeout duration

2. Add a Scheduled Task to Send Heartbeat Packets on Frontend or Backend:

//Scheduled task, because using nginx reverse proxy, 60 seconds without data transmission will disconnect
timer=setInterval(function() {
	if (websocket.readyState == 1) {
		websocket.send("Heartbeat check");
	} else {
		//IM connection has disconnected
	}
}, 50 * 1000);

I used both methods: First, changed the timeout to one hour. Then had the frontend send a heartbeat to the backend every half hour, with the backend responding to the heartbeat.

Chrome Plugin WebSocket Test