Jetty 8.1.1 Websocket客户端握手
我正在使用Jetty 8.1.1 Websocket客户端API。
我需要用("Sec-WebSocket-Protocol", "xsCrossfire")
和("Authorization", "Basic TLVWQMZqRr2hasYnZoI=")
更新标题
WebSocketClientFactory factory = new WebSocketClientFactory(); factory.start(); client = factory.newWebSocketClient(); client.getCookies().put("Sec-WebSocket-Protocol", "xsCrossfire"); client.getCookies().put("Authorization", "Basic TLVWQMZqRr2hasYnZoI="); Future conn = client.open(uri, (WebSocket) this); System.out.printf("Connecting to : %s%n", uri);
请求看起来:
Host: iltlvl262:8000\r\n Upgrade: websocket\r\n Connection: Upgrade\r\n Sec-WebSocket-Version: 13\r\n Sec-WebSocket-Key: FHKTsICO2vqGCxXVwLkH4Q==\r\n Cookie: Sec-WebSocket-Protocol=xsCrossfire\r\n Cookie: Authorization="Basic TLVWQMZqRr2hasYnZoI="\r\n
预期要求:
Host: iltlvl262:8000\r\n Upgrade: websocket\r\n Connection: Upgrade\r\n Sec-WebSocket-Version: 13\r\n Sec-WebSocket-Key: FHKTsICO2vqGCxXVwLkH4Q==\r\n Sec-WebSocket-Protocol: xsCrossfire\r\n Authorization: "Basic TLVWQMZqRr2hasYnZoI="\r\n
如何正确实现8.1.1版中的握手?
一些好消息和一些坏消息。
一,好消息:
要设置Sec-WebSocket-Protocol
标头,请使用以下命令。
client.setProtocol("xsCrossfire");
在使用client.open()
接下来,坏消息:
使用Jetty 8.x,您无法设置任意非websocket标头。 这是由于WebSocket的早期实验草案是如何编写的。 根据早期草案规范,您根本不允许设置任意标头,因此Jetty 8.x天后的实现只是不允许它。
然而,随着RFC6455 (官方WebSocket规范)的最终化改变,所有这些更改都被转移到了Jetty 9.x代码库中。 这是100%符合RFC6455的 。 (注意:Jetty 8在服务器端100%兼容RFC6455。Jetty 8在服务器和客户端的RFC6455协议上也是100%兼容的。但是,Jetty 8在客户端只是部分兼容,从function和API的观点。)
Jetty 7和Jetty 8的决定是为那些仍在使用它们的早期采用者和旧浏览器(Safari 5.x)保留旧的实验草案。 这一决定阻止我们允许在旧的实验草案中特别阻止的行为。
从Jetty 9.x开始,所有旧的websocket实验草稿都被删除,只留下RFC6455支持,这使得Jetty可以打开更多以前不允许的function。 这包括WebSocketClient上的任意标头。
Jetty 9.1 WebSocket客户端的示例
import java.io.IOException; import java.net.URI; import java.util.concurrent.Future; import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.api.WebSocketAdapter; import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; import org.eclipse.jetty.websocket.client.WebSocketClient; public class ExampleClient { public static class ExampleSocket extends WebSocketAdapter { @Override public void onWebSocketText(String message) { try { // echo the message getRemote().sendString(message); } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { try { new ExampleClient().demo(); } catch (Throwable t) { t.printStackTrace(System.err); } } public void demo() throws Exception { WebSocketClient client = new WebSocketClient(); try { client.start(); ClientUpgradeRequest request = new ClientUpgradeRequest(); request.setSubProtocols("xsCrossfire"); request.setHeader("Authorization","Basic TLVWQMZqRr2hasYnZoI="); URI wsUri = URI.create("ws://iltlvl262:8000/echo"); ExampleSocket socket = new ExampleSocket(); Future future = client.connect(socket,wsUri,request); future.get(); // wait for connect socket.getRemote().sendString("hello"); // send message } finally { client.stop(); } } }
另请注意,从Jetty 9.1开始,甚至完全支持javax.websocket
(JSR-356)API。
在Jetty 9.1上使用javax.websocket的相同示例
import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.websocket.ClientEndpoint; import javax.websocket.ContainerProvider; import javax.websocket.OnMessage; import javax.websocket.Session; import javax.websocket.WebSocketContainer; public class ExampleClient { @ClientEndpoint(subprotocols = { "xsCrossfire" }, configurator = ExampleClient.Configurator.class) public static class ExampleSocket { @OnMessage public String onMessage(String msg) { return msg; // echo } } public static class Configurator extends javax.websocket.ClientEndpointConfig.Configurator { @Override public void beforeRequest(Map> headers) { List authvalues = new ArrayList<>(); authvalues.add("Basic TLVWQMZqRr2hasYnZoI="); headers.put("Authorization", authvalues); super.beforeRequest(headers); } } public static void main(String[] args) { try { new ExampleClient().demo(); } catch (Throwable t) { t.printStackTrace(System.err); } } public void demo() throws Exception { WebSocketContainer client = ContainerProvider.getWebSocketContainer(); ExampleSocket socket = new ExampleSocket(); URI wsUri = URI.create("ws://iltlvl262:8000/echo"); Session session = client.connectToServer(socket,wsUri); session.getAsyncRemote().sendText("Hello"); } }