javascript - JavaScript 和 jetty 嵌入式 Websocket 服务器之间的 Websocket 困境

标签 javascript java websocket jetty java-websocket

我有一个 javascript API,它包含在一些网站中。由于某些原因,需要将浏览器端与用 Java 编写的桌面应用程序进行通信。正如您所看到的,所有内容都是主机本地的。

我的第一个解决方案是为每个已知浏览器使用插件/扩展,但缺乏良好的支持和大量依赖项阻止我选择该选项。然后我的第二种方法是双方都使用websockets,服务器在Java应用程序中,客户端是浏览器,一切都会很完美,但随后一个大问题浮出水面: HTTPS 网站无法与不安全的 websocket 服务器建立连接,无论 Java 的情况如何,也无论服务器是否位于本地主机上。

我一直在使用的java_websocket API不足以解决这个问题,而在谷歌中,Jetty是一个听起来适合我的目的的好名字。我在几个小时内开始使用 Jetty,在一些示例之后我得到了两个类,一个服务器端点 (EchoSocket) 和服务器 (EventServer):

EventServer.java

import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;

public class EventServer {

  public static void main(String[] args) {

      try {
        Server server = new Server();
        int httpsPort = 8771;

        SslContextFactory scf = new SslContextFactory("mykeystore.jks");
        scf.setKeyStorePassword("blaStore");
        scf.setKeyManagerPassword("blablaKey");

        SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(scf, "http/1.1");

        HttpConfiguration https = new HttpConfiguration();
        https.setSecurePort(httpsPort);
        https.setSecureScheme("https");
        https.addCustomizer(new SecureRequestCustomizer());

        ServerConnector sslConnector = new ServerConnector(server,
                sslConnectionFactory,
                new HttpConnectionFactory(https)
        );
        sslConnector.setPort(httpsPort);
        server.addConnector(sslConnector);

        HandlerList baseHandler = new HandlerList();
        server.setHandler(baseHandler);

        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); //ServletContextHandler.SESSIONS
        context.setContextPath("/");
        baseHandler.addHandler(context);

        ServerContainer jsrContainer = WebSocketServerContainerInitializer.configureContext(context);
        jsrContainer.addEndpoint(EchoSocket.class);
        baseHandler.addHandler(new DefaultHandler());

        server.start();
        server.dump(System.err);
        server.join();

      } catch (Throwable ex) {
         ex.printStackTrace(System.err);
     }
  }
}

EchoSocket.java

import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value="/echo")
public class EchoSocket
{
    @OnMessage
    public void onMessage(javax.websocket.Session session, String message){
        session.getAsyncRemote().sendText("welcomeeee");
    }

    @OnError
    public void onError(Throwable cause)
    {
        cause.printStackTrace(System.err);
    }

}

使用 Websocket online test我可以从 Mozilla FirefoxOpera 进行通信,但几分钟后连接就会断开,有时会出现未定义的错误导致连接关闭。

如果 Microsoft EdgeIE 不起作用,当我将 URI 写为 wss://localhost:8771/echo 时错误是:

SCRIPT12017: WebSocket Error: SECURITY_ERR, Cross zone connection not allowed

当我尝试使用 wss://127.0.0.1:8771/echo 时,错误是:

SCRIPT12038: WebSocket Error: Network Error 12038, The host name in the certificate is invalid or does not match

Google Chrome 中,这两种 URI 似乎都不起作用,没有连接,错误是:

WebSocket connection to 'wss://127.0.0.1:8771/echo' failed: Error in connection establishment: net::ERR_NETWORK_CHANGED

在另一种情况下:

WebSocket connection to 'wss://localhost:8771/echo' failed: Error in connection establishment: net::ERR_CONNECTION_CLOSED

所以,我需要一些帮助,但也许你可以回答我接下来的一些问题:

  • 我的 Jetty 示例正确吗?如果不正确,我该如何更正它?
  • 我应该尝试其他库或旧版本的 Jetty 才能在大多数浏览器中使用此功能吗?
  • 我应该看看其他语言(例如 C#)中的 Websocket 服务器的其他实现吗?
  • 我必须在 SSL 证书中设置什么主机名或主题备用名称才能允许来自 IE 和 Edge 的连接?也许是“localhost”或“127.0.0.1”。

请提前致谢,抱歉我的英语。

最佳答案

根据经验,浏览器中的 WebSocket 通过 JavaScript 无法与浏览器不知道的 wss:// 加密主机一起使用(证书未由 CA 签名,该 CA 无法识别该主机)浏览器正在使用)

自签名是不可能的,除非您也将证书链添加到浏览器。

这主要是因为它是一个 API,因此没有 GUI 允许您接受证书以绕过浏览器中的安全限制(对于不属于它所了解的 CA 的证书)

Note: Sometimes (but not always) you can get around this certificate restriction, temporarily, by having a normal https://localhost/index.html lookup before you attempt to access the wss://localhost..., allowing you to accept the Certificate for that session.

其他一些新闻:

关于javascript - JavaScript 和 jetty 嵌入式 Websocket 服务器之间的 Websocket 困境,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39132273/

相关文章:

javascript - 尝试从排列的 JSON 键中删除引号

javascript - react JS Bootstrap JS 不工作

javascript - 猫头鹰轮播将最后一项循环回第一项

java - 第一次调用prepareStatement工作正常,但第二次调用java.sql.SQLException : Connection has already been closed

java - Spring 对方法的安全注释是如何工作的?

java - 在 Java 中将二进制数据编码为 ASCII

javascript - 多次更改一张图片的边框

golang websocket如何在浏览器意外关闭时得到通知

node.js - 如何初始化socket.io的实例?

javascript - 实时显示日期时间时出现问题(JavaScript/JQuery)