A browser WebSocket does not send plain text directly over a raw TCP socket. It performs an HTTP upgrade and wraps each message in a WebSocket frame, so reading those bytes as a string produces headers, masking data, and apparently random characters.
Last updated: October 18, 2026.
import jakarta.websocket.OnMessage;
import jakarta.websocket.server.ServerEndpoint;
@ServerEndpoint("/messages")
public class MessageEndpoint {
@OnMessage
public String onMessage(String message) {
System.out.println(message);
return "Received: " + message;
}
}Deploy the endpoint in a Jakarta WebSocket-compatible server and connect the browser to ws://host/messages or wss://host/messages. The container performs framing, unmasking, and text decoding.
Separate protocol framing from character encoding
MDN documents that WebSocket.send() encodes a JavaScript string as UTF-8 inside a text frame. The browser also masks client-to-server frames as required by the protocol. A raw InputStream.read() sees the WebSocket frame, not only the application payload.
Use a WebSocket library or server container rather than implementing the protocol with a plain ServerSocket. The Jakarta WebSocket specification defines annotated server endpoints and permits an @OnMessage method to receive a String for a text message. This also handles fragmented messages and control frames.
Verify the message type on both ends
In the browser, send a string when the server expects text. Sending an ArrayBuffer, typed array, or Blob creates a binary frame and needs a binary message handler on the server. Set the browser’s binaryType only for incoming binary data.
Use developer tools to inspect the WebSocket handshake and Frames or Messages view. A successful HTTP 101 response confirms the upgrade; a normal HTTP 200 response does not. For production, use TLS through wss:, enforce an origin policy and authentication, validate message size, and close malformed sessions.
Continue with understanding UTF-8 and legacy encodings, fixing invalid UTF-8 in JSON, and tracing browser-side JavaScript failures.