Jetty 11 安全 WebSocket(WSS)服务端完整配置指南

老宇君_8438

老宇君_8438

2026-08-08

868人浏览

原创

Jetty 11 安全 WebSocket(WSS)服务端完整配置指南

本文详解如何在 jetty 11 中正确配置单端口 https/wss 服务,解决 ssl 握手失败、http/https 端口分离、websocket 未启用 tls 等典型问题,并提供可直接运行的生产级代码示例。

本文详解如何在 jetty 11 中正确配置单端口 https/wss 服务,解决 ssl 握手失败、http/https 端口分离、websocket 未启用 tls 等典型问题,并提供可直接运行的生产级代码示例。

在 Jetty 11 中搭建安全的 WebSocket 服务(即 wss:// 协议),关键在于统一 TLS 层、复用单一 HTTPS 连接器,并确保 WebSocket 升级请求经由加密通道处理。你遇到的 “SSL handshake error” 和端口分离问题,根源在于错误地初始化了两个独立连接器(一个纯 HTTP,一个 SSL),而 Jetty 的 WebSocket Servlet 默认仅绑定到 HTTP 连接器——它无法自动感知或接管 SSL 连接器上的流量。

✅ 正确架构:单端口 HTTPS + WSS 复用

Jetty 11 不再推荐为 HTTP 和 HTTPS 分别创建连接器。正确的做法是:

  • 仅创建一个 ServerConnector,使用 SslConnectionFactory + HttpConnectionFactory 组合;
  • 所有流量(包括 / 的静态资源、/ws 的 WebSocket 升级请求)均走同一 HTTPS 端口;
  • WebSocket 升级握手(Upgrade: websocket)天然兼容 HTTPS,无需额外协议桥接。

⚠️ 注意:JettyWebSocketServlet 本身不处理 TLS;TLS 由 SslConnectionFactory 在连接层完成。只要 WebSocket 端点注册在 HTTPS 连接器上,浏览器发起 wss://host:port/ws 请求时,整个握手和后续帧传输均自动加密。

? 修正后的完整配置代码(Jetty 11.0.15+)

import org.eclipse.jetty.server.*;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.websocket.server.JettyWebSocketServlet;
import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory;

public class SecureWebSocketServer {
    private final Server server;
    private final int port;

    public SecureWebSocketServer(int port, String keyStorePath, String keyStorePassword) {
        this.port = port;
        this.server = new Server(); // ❌ 不传 port!避免隐式创建默认 HTTP 连接器

        // 1. 配置 SSL 上下文工厂(推荐使用 PKCS12,兼容性更好)
        SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
        sslContextFactory.setKeyStorePath(keyStorePath);
        sslContextFactory.setKeyStorePassword(keyStorePassword);
        sslContextFactory.setKeyManagerPassword(keyStorePassword); // 若密钥密码不同,请单独设置

        // 2. 配置 HTTPS 连接器(单端口,同时支持 HTTP/1.1 和 WebSocket Upgrade)
        HttpConfiguration httpsConfig = new HttpConfiguration();
        httpsConfig.addCustomizer(new SecureRequestCustomizer()); // 启用安全头(如 HSTS)

        ServerConnector httpsConnector = new ServerConnector(
            server,
            new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
            new HttpConnectionFactory(httpsConfig)
        );
        httpsConnector.setPort(port); // ✅ 显式设置端口
        httpsConnector.setIdleTimeout(30_000);

        server.addConnector(httpsConnector);

        // 3. 注册 WebSocket Servlet(路径 "/" 或 "/ws" 均可,客户端用 wss://host:port/ws)
        ServletContextHandler context = new ServletContextHandler();
        context.setContextPath("/");

        JettyWebSocketServlet wsServlet = new JettyWebSocketServlet() {
            @Override
            protected void configure(JettyWebSocketServletFactory factory) {
                factory.addMapping("/ws", (req, res) -> new EchoWebSocketHandler());
                // 可选:添加健康检查或静态页面支持
                factory.getServletContext().addServlet("default", "org.eclipse.jetty.servlet.DefaultServlet")
                       .addMapping("/");
            }
        };
        context.addServlet(new ServletHolder(wsServlet), "/ws");

        server.setHandler(context);
    }

    public void start() throws Exception {
        server.start();
        System.out.printf("✅ Secure WebSocket server started on wss://localhost:%d/ws%n", port);
        server.join();
    }

    // 示例 WebSocket 处理器(回显)
    public static class EchoWebSocketHandler extends WebSocketHandler {
        @Override
        public void onWebSocketConnect(Session session) {
            System.out.println("? Client connected: " + session.getRemoteAddress());
        }

        @Override
        public void onWebSocketText(Session session, String message) {
            try {
                session.getRemote().sendString("Echo: " + message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        // 替换为你的证书路径(建议使用 PKCS12 格式:keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.p12 -deststoretype pkcs12)
        String keystore = "src/main/resources/keystore.p12";
        String password = "changeit";

        new SecureWebSocketServer(8443, keystore, password).start();
    }
}

? 关键配置说明与避坑指南

项目 正确做法 错误做法 后果
Server 初始化 new Server()(无参) new Server(port) 后者会隐式创建一个非 SSL 的 HTTP 连接器,导致端口冲突和流量分流
证书格式 优先使用 .p12(PKCS12),设置 setKeyStoreType("PKCS12") 仅用 JKS 且未设类型 Jetty 11 默认尝试 PKCS12,JKS 需显式声明,否则加载失败
WebSocket 路径 注册在 /ws,客户端访问 wss://host:8443/ws 注册在 / 并期望 wss://host:8443/ 部分浏览器对根路径升级支持不稳定,推荐明确子路径
SSL 协议控制 在 SslContextFactory 中禁用弱协议:
sslContextFactory.setExcludeProtocols("SSL", "SSLv2", "SSLv3");
依赖默认值 避免 TLS 1.0/1.1 等已被弃用协议,满足 PCI DSS 和现代浏览器要求
客户端测试 使用浏览器 wss://localhost:8443/ws 或 wscat -c wss://localhost:8443/ws 尝试 ws:// 连接 HTTPS 端口 协议不匹配,立即断连

?️ 安全加固建议(生产环境必备)

  1. 证书验证:确保证书由可信 CA 签发(或自签名证书已导入客户端信任库),避免 NET::ERR_CERT_AUTHORITY_INVALID;
  2. CORS 控制:在 JettyWebSocketServletFactory 中设置允许源:
    factory.getServletContext().setAttribute("org.eclipse.jetty.websocket.server.WebSocketCreator",
        (HttpServletRequest req, HttpServletResponse resp) -> {
            String origin = req.getHeader("Origin");
            if ("https://trusted-domain.com".equals(origin)) {
                resp.setHeader("Access-Control-Allow-Origin", origin);
            }
            return new EchoWebSocketHandler();
        });
  3. 会话超时:调用 session.setIdleTimeout(60_000) 防止长连接耗尽资源;
  4. 日志监控:启用 Jetty 访问日志并过滤 WSS UPGRADE 请求,快速定位握手失败原因。

✅ 验证是否成功

启动服务后,执行以下任一验证:

WebSocket 8.18.2
WebSocket 8.18.2

WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。

下载
  • 浏览器打开 https://localhost:8443/(应显示 404,证明 HTTPS 工作);
  • 在浏览器控制台运行:
    const ws = new WebSocket("wss://localhost:8443/ws");
    ws.onopen = () => console.log("✅ WSS connected");
    ws.onmessage = e => console.log("←", e.data);
    ws.send("Hello from browser!");
  • 使用命令行工具:
    wscat -c wss://localhost:8443/ws --no-check  # 自签名证书需加 --no-check

? 提示:若使用自签名证书,Chrome/Firefox 会阻止未手动信任的 wss:// 连接。开发阶段可先访问 https://localhost:8443 并点击“高级 → 继续前往”,使证书被临时信任。

通过以上配置,你将获得一个符合现代安全标准(TLS 1.2+、强密码套件、单端口复用)的 Jetty 11 WSS 服务,彻底规避握手失败与端口混乱问题,为实时通信筑牢加密基石。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

websocket

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
OpenJDK JVM参数怎么调优
OpenJDK JVM参数怎么调优

Java应用运行缓慢,如何调整JVM参数?本专题介绍OpenJDK JVM性能调优的基本流程,涵盖性能指标确认、运行数据采集、内存配置和垃圾回收分析,帮助你先定位瓶颈,再通过对照测试验证效果,避免直接套用参数而影响应用稳定性。

2026.10.16

0

10

OpenJDK怎么配置Java开发环境
OpenJDK怎么配置Java开发环境

怎样用OpenJDK搭建开发环境?本专题介绍版本选择、下载安装、环境变量配置和编译运行验证,帮助你理清JDK的作用及基本配置流程,并通过简单程序检查环境是否可用,为后续项目开发做好准备。

2026.10.16

0

10

OpenJDK怎么部署Java应用
OpenJDK怎么部署Java应用

Java项目开发完成后,怎样部署到目标环境并正常运行?本专题介绍OpenJDK应用部署流程,涵盖运行环境准备、版本兼容检查、应用打包、启动参数配置和日志查看,帮助你理清部署前后的操作顺序,减少环境差异造成的运行问题。

2026.10.16

0

10

Revel框架模板渲染与表单验证
Revel框架模板渲染与表单验证

本专题围绕Revel框架视图层开发,介绍模板语法、变量输出、布局复用、表单提交、参数绑定与验证规则,帮助开发者完成安全规范的页面交互。

2026.10.16

0

15

Revel框架MVC路由与控制器
Revel框架MVC路由与控制器

本专题聚焦Revel框架MVC核心机制,讲解路由定义、控制器Action、参数绑定、请求响应和反向路由,并结合常见场景梳理接口请求处理流程。

2026.10.16

0

15

Revel框架入门与安装配置
Revel框架入门与安装配置

本专题从Revel框架环境搭建讲起,系统介绍命令行工具安装、项目创建、目录结构、配置文件及热代码重载,帮助开发者快速完成首个Go Web应用。

2026.10.16

0

15

Linux 新手先学哪些命令
Linux 新手先学哪些命令

Linux新手命令专题汇集终端基础、文件目录操作、文本查看、软件安装和权限管理等入门文章,帮助按实际任务练习常用命令并建立命令行操作习惯。

2026.10.15

0

20

MySQL 忘记密码怎么办
MySQL 忘记密码怎么办

MySQL忘记密码专题汇集不同版本与系统下的root密码重置方法,覆盖MySQL 5.7、8.0、Mac、Linux及本地集成环境,并提示恢复权限与重新登录的检查步骤。

2026.10.15

0

18

Vue.js 中 ref 和 reactive 的区别
Vue.js 中 ref 和 reactive 的区别

Vue.js中ref和reactive的区别专题汇集两种响应式API的定义、访问方式、对象解构、侦听与性能取舍等文章,帮助结合实际状态类型选择合适写法。

2026.10.15

0

20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WebSocket手册
WebSocket手册

共0课时 | 0人学习

Webman中文手册
Webman中文手册

共0课时 | 0人学习