TOMCAT-服务器在tomcat8.5上使用HTTP2发送的事件,没有异步Servlet



我们已经在Asyncservlet上遇到了一些问题,因此我们研究了SSE和WebSockets。

SSE的所有tomcat示例看起来都如:

@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //content type must be set to text/event-stream
        response.setContentType("text/event-stream"); 
        //cache must be set to no-cache
        response.setHeader("Cache-Control", "no-cache");     
        //encoding is set to UTF-8
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = response.getWriter();
        for(int i=0; i<10; i++) {
            System.out.println(i);
            writer.write("data: "+ i +"nn");
            writer.flush();
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        writer.close(); 
    }
}

但是,我想保持连接长时间的运行期,希望不必保持线程处理请求。这是从pubsubhub接收信息并希望将其推向浏览器的一个示例。

@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //content type must be set to text/event-stream
        response.setContentType("text/event-stream"); 
        //cache must be set to no-cache
        response.setHeader("Cache-Control", "no-cache");     
        //encoding is set to UTF-8
        response.setCharacterEncoding("UTF-8");
        final PrintWriter writer = response.getWriter();
        PublishSubsribeHub.getInstance().subscribe("TestData", new Callback(String msg){
           public void run(){
               writer.write("data:"+msg);
               writer.flush(); // this throws NullPointerException since undeline HttpServletResponse is closed
           });
}

就像上面的评论中提到的那样,数据已准备就绪并通过PublishSubsribeHub接收,连接已关闭。

"修复"的方法是使用响应。StartAsync(),它可以保持连接打开。

但是,我们的问题完全符合这种机制" asynconcontext"/" asyncservlet"。因此,想知道(在我切换到tomcat的Websocket Impl之前)是否还有其他方法支持使用tomcat8.5或tomcat9的async推消息,也许使用http/2 spec。

谢谢

如果在项目的上下文中可行,请考虑使用泽西库库以启用SSE功能。

泽西岛是一种流行,易于使用且文化良好的解决方案。此外,该文档还包含有关如何使用库的明确示例。您可以在下面找到这样的示例。

广播示例

import org.glassfish.jersey.media.sse.SseBroadcaster;
@Singleton
@Path("broadcast")
public static class BroadcasterResource {
    private SseBroadcaster broadcaster = new SseBroadcaster();
    @POST
    @Produces(MediaType.TEXT_PLAIN)
    @Consumes(MediaType.TEXT_PLAIN)
    public String broadcastMessage(String message) {
        OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
        OutboundEvent event = eventBuilder.name("message")
            .mediaType(MediaType.TEXT_PLAIN_TYPE)
            .data(String.class, message)
            .build();
        broadcaster.broadcast(event);
        return "Message '" + message + "' has been broadcast.";
    }
    @GET
    @Produces(SseFeature.SERVER_SENT_EVENTS)
    public EventOutput listenToBroadcast() {
        final EventOutput eventOutput = new EventOutput();
        this.broadcaster.add(eventOutput);
        return eventOutput;
    }
}

这个特定示例使用了一个广播员:

  • 允许客户端通过" ListEntobroadcast"方法订阅。
  • 使用"广播媒介"方法向每个订阅客户端广播消息。

运行示例

为了运行示例,请按照以下步骤:

  • 为SSE类创建一个新软件包
  • 在此软件包中,基于上述广播示例
  • 创建类
  • 添加另一个能够自动发现(并注册)同一软件包中的类:

-

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("api")
public class ApiConfig extends Application { 
}

用Tomcat 7、8、8.5测试了上述溶液。使用:2.x

的泽西岛版本

最新更新