The spec forbids reading the HTTP status code (or anything like it) from the WebSocket object because otherwise the WebSocket object could be used to probe non-WebSocket endpoints, which would be a security issue:
User agents must not convey any failure information to scripts in a way that would allow a script to distinguish the following situations:
- A server whose host name could not be resolved.
- A server to which packets could not successfully be routed.
- A server that refused the connection on the specified port.
- A server that failed to correctly perform a TLS handshake (e.g., the server certificate can't be verified).
- A server that did not complete the opening handshake (e.g. because it was not a WebSocket server).
- A WebSocket server that sent a correct opening handshake, but that specified options that caused the client to drop the connection (e.g. the server specified a subprotocol that the client did not offer).
- A WebSocket server that abruptly closed the connection after successfully completing the opening handshake.
— https://www.w3.org/TR/websockets/#feedback-from-the-protocol
There is another way to do it though!
The WebSocket protocol allows for custom close codes:
4000-4999
Status codes in the range 4000-4999 are reserved for private use and thus can't be registered. Such codes can be used by prior agreements between WebSocket applications. The interpretation of these codes is undefined by this protocol.
— https://www.rfc-editor.org/rfc/rfc6455#section-7.4.2
In your server-side logic, even when you ultimately want to reject the connection (like say the user is currently unauthenticated), do this instead:
- Accept the WebSocket connection
- Immediately close the connection with a custom close status
The client can now look at the CloseEvent.code to know why the connection was rejected.
You don't need to do this every time the server wants to reject a WebSocket connection. For example, I'd still reject the connection with a 4xx HTTP status if the request isn't a proper WebSocket request, or for security reasons (like if the anti-CSWSH Origin check fails). You only need to use the WebSocket close status for cases that you want the client-side logic to handle.