Websocket握手在Java中失败
所以,我正在尝试解析一个使用websocket向客户端发送数据的网站。 从我读过的内容:
- 链接1
- 链接2
我知道,为了创建连接,我需要向服务器发送一个特殊的http请求,然后我将检索一些用于访问该通道的数据。
我做了什么:
-
创建了http请求
`URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); // optional default is GET con.setRequestMethod("GET"); //add request header con.setRequestProperty("Cache-Control", "no-cache"); con.setRequestProperty("Host", "www.example.com"); con.setRequestProperty("Upgrade", "websocket"); con.setRequestProperty("Connection", "upgrade"); con.setRequestProperty("Origin", "https://example.com"); con.setRequestProperty("Sec-WebSocket-Extensions", "x-webkit-deflate-frame"); con.setRequestProperty("Sec-WebSocket-Key", "QkWkChtTGpaZL5PkOMaRtg=="); con.setRequestProperty("Sec-WebSocket-Version", "13"); con.setRequestProperty("User-Agent", "Mozilla/..;
`
我用代码200(不应该是101)读取响应。
问题:
- 我如何生成Sec-Websocket-Key? (例如从firebug中获取,实际上所有头文件)
1.1。 还有什么可以做的?
1.2。 必须使用http中的相同链接来访问websocket? 只用wss而不是https?
-
在此之后,我尝试将客户端连接到服务器并在onMessage方法中接收消息。
WebSocketContainer container = ContainerProvider.getWebSocketContainer(); Session session = container.connectToServer(ClientEndpoint.class, buildCEC(), new URI("wss://async.example.com/socket.io/1/?t=" + System.currentTimeMillis()));
-
我尝试在buildCec()中插入标题以连接到服务器。
ClientEndpointConfig config = ClientEndpointConfig.Builder.create().build(); Configurator conf = config.getConfigurator();
`Map<String, List> headers = new HashMap<String, List>(); headers.put("Connection", Arrays.asList("keep-alive", "Upgrade")); headers.put("Sec-Websocket-Extensions", Arrays.asList("x-webkit-deflate-frame")); headers.put("Sec-Websocket-key", Arrays.asList("cx36sHrtuW9HZAaB6kKa/Q==")); headers.put("Sec-Websocket-Version", Arrays.asList("13")); headers.put("Upgrade", Arrays.asList("websocket")); headers.put("User-Agent", Arrays.asList("Mozill...")); conf.beforeRequest(headers); return config;`
问题
- 我的判断是好的,以防我解决并从http升级请求中收到101状态代码?(我的意思是,我接下来要做的是什么细节?)
- 请不要评判我,我刚开始使用java中的websockets,我不太了解javascript,我想用jsr-356在纯java中做这个客户端。 我用websockets做了一些小例子,但我找不到一个好的客户端,有标题和更复杂的握手。
- 是否可以连接到未知服务器,不知道所有细节?
我正在使用一个编程端点并导入javax.websocket.ContainerProvider; 用于处理来自jsr356的websocket连接。
这里有很多主题。
- 不要将URLHttpConnection用于WebSocket,它根据HTTP语义管理输出/输入流,不处理升级连接。 使用标准sockets。
- 阅读RFC-6455:WebSocket协议
- 在RFC6455中多次提到
Sec-WebSocket-Key
,它有1个总体目的,客户端可以certificate它从服务器接收到有效的WebSocket打开握手 。 客户端有规则,服务器端有关于它应该做什么的规则,以及它应该如何响应它。 (简而言之,它是客户端选择的随机值,发送到服务器,服务器在此步骤的RFC指定GUID上计算,计算SHA-1哈希,并在其自己的Sec-WebSocket-Key
使用此哈希进行响应,客户端validation以确认服务器是否真的支持WebSocket) - 阅读第5.2节。 基本框架协议仔细,特别是3种有效负载长度的部分(你必须实现对所有3的支持,因为服务器需要规则来validation这一点)’ – 请参阅其他答案 – Java Websocket Text Frame Error > = 128?
- 至于
javax.websocket.server.ServerEndpointConfig.Configurator
,您无法调用这些方法。 这些是在建立连接的过程中由JSR-356 websocket服务器实现调用的。 请参阅我关于此过程的其他答案 – 在Web Socket @ServerEndpoint中从HttpServletRequest访问HttpSession - 请注意框架validation规则 – 如何在Java中解析和validationWebSocket框架?
我知道有几个JSR-356独立客户端。
- Eclipse Jetty 9.1+
org.eclipse.jetty.websocket javax-websocket-client-impl 9.1.0.v20131115
- Apache Tomcat 8.0+
org.apache.tomcat tomcat-websocket 8.0.0-RC5 org.apache.tomcat tomcat-coyote 8.0.0-RC5
- 灰熊计划
org.glassfish.grizzly grizzly-websockets 2.3.8
- Glassfish Tyrus
org.glassfish.tyrus.bundles tyrus-standalone-client 1.3.3
如果您确实编写了自己的WebSocket客户端,请确保您针对Autobahn WebSocket Protocol Testsuite进行测试(每个人都针对此测试套件编写实现测试,它有点成为事实上的协议validation套件)
我想这就是你需要的:
String secAccept = sha1base64(secKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); private String sha1base64(String str) { MessageDigest md = null; try { md = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return Base64.encode(md.digest(str.getBytes())); }