让 Jetty Websocket 使用与 JavaScript Websocket 相同的语言

Posted

技术标签:

【中文标题】让 Jetty Websocket 使用与 JavaScript Websocket 相同的语言【英文标题】:Getting Jetty Websocket talking same language as JavaScript Websocket 【发布时间】:2020-04-07 18:17:01 【问题描述】:

我编写了一个 Jetty Websocket 客户端,它连接到远程服务器并尝试发送 JSON 请求。服务器拒绝请求无效并关闭我的连接。但是,当我使用 javascript 客户端发送完全相同的 JSON 时,它工作得很好。所以现在我不禁摸不着头脑,是杰克逊 2 对 JSON 与 JSON.stringify() 的编码吗? (差异显示两个 JSON 输出完全相同,没有差异)。 Javascript Websockets 和 Jetty 之间的默认配置是否不同?我肯定错过了什么,我的头撞在墙上。

Java 端代码段:

final String wsAddress = "ws://" + wssUrl + "/ws";
    final WebSocketClient client = new WebSocketClient();
    final WSEventSocket socket = new WSEventSocket(loginRequest);
    try 
        client.start();

        final ClientUpgradeRequest request = new ClientUpgradeRequest();
        final URI wsUri = new URI(wsAddress);

        logger.info("Connecting to ", wsUri);
        final Future<Session> session = client.connect(socket, wsUri, request);

        final String requestjson = mapper.writeValueAsString(wsRequestPojo);
        final Future<Void> fut = session.getRemote().sendStringByFuture(requestjson);
...

Javascript端sn-p:

var wsRequestJson = ...Use output from Java Side...
var mySock = new WebSocket("ws://" + wsocketUrl + "/ws");
mySock.onmessage = function(evt)  console.log(evt.data); ; mySock.onclose = function()  console.log("CLOSED"); ;
mySock.send(JSON.stringify(wsRequestJson));

Javascript 端完美运行,Java 端未正确编码数据。我已经尝试过很多东西,比如 JSON 到字节数组,但没有运气。我对这两个事务进行了 Wireshark 处理,我看到了 WebSocket 推送和响应。在 Java 中,我看到一个看起来与 JSON 完全一样的有效负载,而 Wireshark 对其进行了解密。在 Javascript 数据包中,我看到了某种类型的编码数据 \214P\311n\3020\024... 我读了一些关于 Masked Payloads 的内容,两个客户端都在发送带有 Masking-Keys 的 Masked Payloads,也许与此有关?

知道如何让 Java Jetty 端以类似的方式对数据进行编码吗?甚至 Javascript 端使用的是什么类型的编码?在这一点上我可能想多了......

谢谢!

【问题讨论】:

你确定payload没有被javascript端压缩吗? (例如:permessage-deflate)来解释为什么你会在 Wireshark 上看到“编码数据”。 看wireshark似乎javascript方面确实在设置Websocket-Extension: premessage-deflate!知道如何在 Jetty 中设置它吗?没有看到任何直接的例子。谢谢! 马上就完美运行了!在 github 上的一个单元测试中找到了一种简单的方法: final ClientUpgradeRequest request = new ClientUpgradeRequest(); request.addExtensions(ExtensionConfig.parse("permessage-deflate")); 【参考方案1】:

正如@Joakim Erdfelt 在上面的评论中所述,Javascript 端默认使用 Sec-Websocket-Extension: permessage-deflate。可能不是设置它的最佳方法,但我通过添加以下内容更新了我的 Java 代码:

request.addExtensions(ExtensionConfig.parse("permessage-deflate"));

更新片段:

final String wsAddress = "ws://" + wssUrl + "/ws";
    final WebSocketClient client = new WebSocketClient();
    final WSEventSocket socket = new WSEventSocket(loginRequest);
    try 
        client.start();

        final ClientUpgradeRequest request = new ClientUpgradeRequest();
        request.addExtensions(ExtensionConfig.parse("permessage-deflate"));
        final URI wsUri = new URI(wsAddress);

        logger.info("Connecting to ", wsUri);
        final Future<Session> session = client.connect(socket, wsUri, request);

        final String requestjson = mapper.writeValueAsString(wsRequestPojo);
        final Future<Void> fut = session.getRemote().sendStringByFuture(requestjson);
...

像魅力一样工作!谢谢!

【讨论】:

以上是关于让 Jetty Websocket 使用与 JavaScript Websocket 相同的语言的主要内容,如果未能解决你的问题,请参考以下文章

Jetty Websocket 连接 - 忽略自签名证书

在类路径中添加库后找不到 Jetty WebSocket 类

嵌入 Jetty 10 的 GraphQL 订阅

Jetty 如何创建自定义 WebSocket

Jetty Websocket连接中未退出的主要方法

Jetty WebSocket 代理