I created a WebSocket server using Java Spring, which worked correctly when connecting via ws://localhost:8080/socket
and ws://localhost:30019/socket
. However, when I attempt to upload the socket to a host and connect to it via ws://website.com/socket
, it cannot connect. The difference in ports (connecting to port 80
on the host despite it running on port 30019
) is due to the host using a proxy server and redirecting port 80 of the proxy to port 30019 of the hosting server. Connecting to the static portion of the page is the same between localhost:30019
and website.com
, where the webpage displays accurately in both cases.
When I try to connect, I receive a WebSocketHandshakeException
due to a 400 response from the server:
Exception in thread "main" java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.net.http.WebSocketHandshakeException
at com.socketsimpl.Main.main(Main.java:34)
Caused by: java.util.concurrent.ExecutionException: java.net.http.WebSocketHandshakeException
at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396)
at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2073)
at com.socketsimpl.Main.main(Main.java:27)
Caused by: java.net.http.WebSocketHandshakeException
at java.net.http/jdk.internal.net.http.websocket.OpeningHandshake.resultFrom(OpeningHandshake.java:226)
at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1150)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
at java.base/java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:614)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:844)
at java.base/java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:483)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: jdk.internal.net.http.websocket.CheckFailedException: Unexpected HTTP response status code 400
at java.net.http/jdk.internal.net.http.websocket.OpeningHandshake.checkFailed(OpeningHandshake.java:343)
at java.net.http/jdk.internal.net.http.websocket.OpeningHandshake.handleResponse(OpeningHandshake.java:252)
at java.net.http/jdk.internal.net.http.websocket.OpeningHandshake.resultFrom(OpeningHandshake.java:222)
... 10 more
When the server returns the 400 code, the error in the server console is "Handshake failed due to invalid Upgrade header: null"
. When switching the log level to debug by adding logging.level.root=DEBUG
to application.properties
, it can be seen that the Upgrade
header is not in the headers list.
To add the header, I changed my connection code from:
HttpClient client = HttpClient.newHttpClient();
socket = client.newWebSocketBuilder()
.buildAsync(
URI.create("ws://website.com/socket"),
new Listener()
)
.get();
to
HttpClient client = HttpClient.newHttpClient();
.header("Connection", "Upgrade")
.header("Upgrade", "WebSocket")
.buildAsync(
URI.create("ws://website.com/socket"),
new Listener()
)
.get();
However, as Connection
and Upgrade
are considered restricted headers by Java, this causes an IllegalArgumentException
with description restricted header name: "Connection"
. As widely suggested across StackOverflow and other websites, I added the allowRestrictedHeaders
property, making my startup command:
java -"Djdk.httpclient.allowRestrictedHeaders=Upgrade,Connection" -jar .\untitled-1.0-SNAPSHOT-all.jar
However, the headers logged in the server console remain the exact same, the error returns to WebSocketHandshakeException
, and the error in the server console also remains the same; it is as if I didn't add the headers. When testing with other headers, they appear in the headers logged in the server console, meaning it is a valid way to add headers.
How can I fix the handshake, allowing the client to successfully connect to the server?