How to stop Java Spring WebSocket connection from immediately closing with EOFException?

I’m working on a web application with an Angular 17 frontend and a Spring Boot backend. I’m trying to set up WebSocket communication on one page in order to receive real time updates from the backend.

Per the boss’ requirements, I’m using the RxJS WebSocket wrapper on the frontend. When I attempt to create the Web Socket connection, I get an error in the Chrome DevTools saying that WebSocket connection to 'wss://localhost:8443/ws' failed. Followed by a Websocket connection closed message.

The server logs seem to indicate that the websocket connection is established, but then immediately ended due to an EOFException: Transport error in StandardWebSocketSession[id=0c2b656b-5081-9312-9ec5-af58f0f6ff29, uri=wss://localhost:8443/ws] java.io.EOFException: null.

The same setup works correctly when I run it in a small demo app, which leads me to believe there is something in the configuration or security settings of my Spring app that is causing this immediate closure/rejection of the websocket connection. What might be causing this error?

Here is my code.
Frontend:

@Injectable({
  providedIn: 'root'
})
export class WebSocketService {
  private socket$: WebSocketSubject<any> | null = null;
  private latestMessage: Signal<any> = signal(null);
  private authToken: string;

  constructor(private authServerProvider: AuthServerProvider) {
    this.authToken = this.authServerProvider.getToken();

    const connectionString = PORTAL_SERVER_API_URL.replace('http', 'ws') + '/ws';
    this.socket$ = this.socket$ = webSocket({
      url: connectionString,
      protocol: ['access_token', this.authToken],
      openObserver: {
        next: () => console.log('WebSocket connection opened')
      },
      closeObserver: {
        next: (closeEvent) => console.log('WebSocket connection closed', closeEvent)
      }
    });

    this.socket$.subscribe({
      next: () => { console.log('Next'); },
      error: (error) => { console.log('Error: ' + error); },
      complete: () => { console.log('Complete'); },
    });

    console.log('Service constructed, socket created');
  }

  sendToServer(request: string) {
    this.socket$.next({
      request,
    });
  }
}

Backend:

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketHandler(), "/ws").setAllowedOrigins("*").addInterceptors(new HttpSessionHandshakeInterceptor());
    }


    @Bean
    public WebSocketHandler webSocketHandler() {
        return new WebSocketController();
    }

    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
        container.setMaxTextMessageBufferSize(8192);
        container.setMaxBinaryMessageBufferSize(8192);
        container.setMaxSessionIdleTimeout(100000L);
        return container;
    }

}
public class WebSocketController extends TextWebSocketHandler {

    private final ObjectMapper objectMapper = new ObjectMapper();
    private static final Logger logger = LoggerFactory.getLogger(WebSocketController.class);

    @Override
    @PreAuthorize("permitAll()")
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
        String payload = message.getPayload();

        Map<String, String> incomingJson = objectMapper.readValue(payload, Map.class);

        // Create a response JSON
        Map<String, String> jsonResponse = new HashMap<>();
        jsonResponse.put("response", incomingJson.get("request"));

        // Convert to JSON string and send
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(jsonResponse)));

    }

    @Override
    @PreAuthorize("permitAll()")
    public void afterConnectionEstablished(WebSocketSession session) {
        logger.debug("WebSocket connection established: " + session.getId());
        logger.debug("Session attributes: " + session.getAttributes());
        logger.debug("Session protocol: " + session.getAcceptedProtocol());
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        logger.error("Transport error on session " + session.getId(), exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        logger.debug("WebSocket connection closed for session " + session.getId() + " with status: " + status);
    }
}

And here is the complete console output:
**Chrome Devtools: **

web-socket.service.ts:33 - WebSocket connection to 'wss://localhost:8443/ws' failed:
WebSocketService @ web-socket.service.ts:33
WebSocketService_Factory @ web-socket.service.ts:46
ExecuteExtractDialogComponent_Factory @ execute-extract-dialog.component.ts:21
openRunDialog @ extracts.component.ts:102
ExtractsComponent_ng_container_25_Template_i_click_17_listener @ extracts.component.html:41
...
Error: [object Event]
WebSocket connection closed
CloseEvent {
isTrusted: true
bubbles: false
cancelBubble: false
cancelable: false
code: 1006
composed: false
currentTarget: WebSocket {__zone_symbol__openfalse: Array(1), __zone_symbol__errorfalse: Array(1), __zone_symbol__ON_PROPERTYopen: ƒ, __zone_symbol__ON_PROPERTYerror: ƒ, __zone_symbol__ON_PROPERTYclose: ƒ, …}
defaultPrevented: false
eventPhase: 0
reason: ""
returnValue: true
srcElement: WebSocket {__zone_symbol__openfalse: Array(1), __zone_symbol__errorfalse: Array(1), __zone_symbol__ON_PROPERTYopen: ƒ, __zone_symbol__ON_PROPERTYerror: ƒ, __zone_symbol__ON_PROPERTYclose: ƒ, …}
target: WebSocket {__zone_symbol__openfalse: Array(1), __zone_symbol__errorfalse: Array(1), __zone_symbol__ON_PROPERTYopen: ƒ, __zone_symbol__ON_PROPERTYerror: ƒ, __zone_symbol__ON_PROPERTYclose: ƒ, …}
timeStamp: 32752.699999999255
type: "close"
wasClean: false
[[Prototype]]: CloseEvent {...}

Spring Boot Server Logs:

2024-07-09 21:18:34,555 63893 [https-jsse-nio-8443-exec-6] TRACE o.s.s.w.a.i.RequestMatcherDelegatingAuthorizationManager - Checking authorization on SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@1c07e08e] using org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer$$Lambda$1740/0x00000008018fd8d0@63647e54

2024-07-09 21:18:34,555 63893 [https-jsse-nio-8443-exec-6] DEBUG o.s.security.web.FilterChainProxy - Secured GET /ws

2024-07-09 21:18:34,556 63894 [https-jsse-nio-8443-exec-6] TRACE o.s.w.s.s.s.WebSocketHandlerMapping - Mapped to HandlerExecutionChain with [org.springframework.web.socket.server.support.WebSocketHttpRequestHandler@41366d50] and 1 interceptors

2024-07-09 21:18:34,557 63895 [https-jsse-nio-8443-exec-6] DEBUG o.s.w.s.s.s.WebSocketHttpRequestHandler - GET /ws

2024-07-09 21:18:34,560 63898 [https-jsse-nio-8443-exec-6] TRACE o.s.w.s.s.s.DefaultHandshakeHandler - Processing request https://localhost:8443/ws with headers=[host:"localhost:8443", connection:"Upgrade", pragma:"no-cache", cache-control:"no-cache", user-agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36", upgrade:"websocket", origin:"https://localhost:4200", sec-websocket-version:"13", accept-encoding:"gzip, deflate, br, zstd", accept-language:"en-US,en;q=0.9", sec-websocket-key:"x2ViimlmVyvdISG3PaOAiQ==", sec-websocket-extensions:"permessage-deflate; client_max_window_bits", sec-websocket-protocol:"access_token, eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJraGF3a2luc0BxdWlja21lZGNsYWltcy5jb20iLCJhdXRoIjoiUk9MRV9TVVBFUl9BRE1JTiIsImV4cCI6MTcyMDY5NDMwMSwibWZhUmVxdWlyZWQiOmZhbHNlfQ.rXglaeJU-IPKBSjLn92eThls2HYx1IgGhC44JE9U8XMZOtgRFPJpvt6E6c_VGlTI48SBTe3CCCWGTRZw-2j5bw"]

2024-07-09 21:18:34,561 63899 [https-jsse-nio-8443-exec-6] TRACE o.s.w.s.s.s.DefaultHandshakeHandler - Upgrading to WebSocket, subProtocol=null, extensions=[]

2024-07-09 21:18:34,626 63964 [https-jsse-nio-8443-exec-6] DEBUG o.s.w.s.h.LoggingWebSocketHandlerDecorator - New StandardWebSocketSession[id=ebef1ca9-ff61-b045-47cc-5227f9c65f68, uri=wss://localhost:8443/ws]

2024-07-09 21:18:34,626 63964 [https-jsse-nio-8443-exec-6] DEBUG c.q.p.c.WebSocketController - WebSocket connection established: ebef1ca9-ff61-b045-47cc-5227f9c65f68

2024-07-09 21:18:34,626 63964 [https-jsse-nio-8443-exec-6] DEBUG c.q.p.c.WebSocketController - Session attributes: {}

2024-07-09 21:18:34,626 63964 [https-jsse-nio-8443-exec-6] DEBUG c.q.p.c.WebSocketController - Session protocol: 

2024-07-09 21:18:34,631 63969 [https-jsse-nio-8443-exec-6] DEBUG o.s.w.s.h.LoggingWebSocketHandlerDecorator - Transport error in StandardWebSocketSession[id=ebef1ca9-ff61-b045-47cc-5227f9c65f68, uri=wss://localhost:8443/ws]
java.io.EOFException: null
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1297)
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1247)
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1191)
    at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:74)
    at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:183)
    at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:163)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:152)
    at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:60)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:57)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
    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:833)

2024-07-09 21:18:34,632 63970 [https-jsse-nio-8443-exec-6] ERROR c.q.p.c.WebSocketController - Transport error on session ebef1ca9-ff61-b045-47cc-5227f9c65f68
java.io.EOFException: null
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1297)
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1247)
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1191)
    at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:74)
    at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:183)
    at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:163)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:152)
    at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:60)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:57)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
    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:833)

2024-07-09 21:18:34,637 63975 [https-jsse-nio-8443-exec-6] DEBUG o.s.w.s.h.LoggingWebSocketHandlerDecorator - StandardWebSocketSession[id=ebef1ca9-ff61-b045-47cc-5227f9c65f68, uri=wss://localhost:8443/ws] closed with CloseStatus[code=1006, reason=null]

2024-07-09 21:18:34,638 63976 [https-jsse-nio-8443-exec-6] DEBUG c.q.p.c.WebSocketController - WebSocket connection closed for session ebef1ca9-ff61-b045-47cc-5227f9c65f68 with status: CloseStatus[code=1006, reason=null]

I’ve tried changing various security configuration settings in the main config class to no avail. This is the current state of the SecurityFilterChain:

@Bean
    public SecurityFilterChain web(HttpSecurity http) throws Exception {
        String[] permitAllPaths = jwtProperties.getPermitAllPaths().toArray(new String[0]);

        var auth1 = AuthorityAuthorizationManager.<RequestAuthorizationContext>hasRole("USER");
        auth1.setRoleHierarchy(roleHierarchy());

        return http.csrf().disable().
                headers().frameOptions().disable().and()
                .cors().configurationSource(request -> getCorsConfiguration()).and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilterAfter(tokenAuthenticationFilter, SecurityContextHolderFilter.class)
                .authorizeHttpRequests().requestMatchers(permitAllPaths).permitAll()
                .requestMatchers("/api/**").authenticated().requestMatchers("/ws/**").permitAll()
                .and()
                .securityContext((securityContext) -> securityContext
                        .securityContextRepository(new RequestAttributeSecurityContextRepository())
                ).authenticationProvider(filteringAuthenticationProvider())
                .build();
    }

New contributor

khh is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật