You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tomcat10.1中用HttpServletRequest.newPushBuilder()实现SSE返回null的问题

关于Jakarta Servlet中PushBuilder返回null及SSE实现的问题

问题描述

我是Server-Sent Events(SSE)实现的新手,尝试使用Java Jakarta HttpServletRequest来实现相关功能,但遇到了req.newPushBuilder()始终返回null的问题。我已经尝试通过自签名证书及Tomcat的server.xml配置切换到HTTP/2,但问题仍未解决。

想咨询以下几个问题:

  1. 是否遗漏了某些实现步骤导致PushBuilder返回null?
  2. 在Tomcat10.1中实现HTTP/2服务器推送(PushBuilder)的必要步骤是什么?
  3. 实现SSE是否必须使用TLS证书,能否在HTTP/1下实现?

附当前测试代码:

import java.io.IOException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.PushBuilder;


@WebServlet("/check-push")
public class PushServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        final String titleText;
        PushBuilder builder = req.newPushBuilder();
        System.out.println(builder);
    }

}

问题解答

1. PushBuilder返回null的常见原因

  • HTTP/2配置未生效:PushBuilder是Servlet 4.0引入的HTTP/2专属特性,若客户端实际未使用HTTP/2协议连接,该方法会直接返回null。
  • 客户端兼容性限制:多数浏览器仅在TLS加密环境下支持HTTP/2,使用自签名证书时可能被浏览器拒绝启用HTTP/2;明文HTTP/2(h2c)仅少数浏览器支持,且需手动开启相关设置。
  • 响应提交时机错误:PushBuilder必须在响应未提交前调用(即未调用resp.getWriter()或resp.getOutputStream()),若响应已被隐式提交,方法也会返回null。

2. Tomcat10.1中配置PushBuilder的必要步骤

  • 正确配置HTTP/2连接器:
    在server.xml中添加支持HTTP/2的NIO2连接器:
    <!-- TLS加密的HTTP/2连接器(生产推荐) -->
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               maxThreads="150" SSLEnabled="true">
        <SSLHostConfig>
            <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
                         type="RSA"/>
        </SSLHostConfig>
        <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol"/>
    </Connector>
    
    <!-- 明文HTTP/2连接器(仅测试用,浏览器兼容性差) -->
    <Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               maxThreads="150">
        <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol"/>
    </Connector>
    
  • 验证HTTP/2连接:
    使用浏览器开发者工具(Network面板)查看请求的Protocol列,确认显示为h2(TLS环境)或h2c(明文环境)。
  • 规范代码调用时机:
    确保在获取响应输出流/写入器之前调用newPushBuilder(),示例:
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 先获取PushBuilder,再处理响应
        PushBuilder builder = req.newPushBuilder();
        if (builder != null) {
            builder.path("/static/css/main.css").push();
        }
        // 之后再处理响应内容
        resp.getWriter().write("Hello World");
    }
    

3. SSE的实现与TLS/HTTP版本的关系

  • SSE不需要依赖HTTP/2或TLS证书,完全可以在HTTP/1.1环境下正常实现。
  • SSE的核心逻辑是设置特定响应头并保持长连接:
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        resp.setContentType("text/event-stream");
        resp.setCharacterEncoding("UTF-8");
        resp.setHeader("Cache-Control", "no-cache");
        resp.setHeader("Connection", "keep-alive");
    
        PrintWriter writer = resp.getWriter();
        // 模拟持续发送事件
        for (int i = 0; i < 5; i++) {
            writer.write("data: 第" + (i+1) + "条SSE消息\n\n");
            writer.flush();
            Thread.sleep(1000);
        }
        writer.close();
    }
    
  • 补充:HTTP/1.1下的SSE受限于浏览器并发长连接数(通常同一域名下最多6个),而HTTP/2的多路复用特性可以解决这个限制,但这属于优化项,而非实现SSE的必要条件。

内容的提问来源于stack exchange,提问作者Maxon Sagnim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:02:26