在 Feat 中使用协议升级
在 Feat 里,协议升级的意义不是“多学一个 API”,而是让同一个 HTTP 服务入口可以承接不同的实时通信模式。
这页的重点不是讲协议标准,而是回答:什么时候该用哪种升级方式,以及在 Feat 里怎么落地。
如果你现在只是知道“我要实时通信”,先不要急着写代码。先判断是哪一类:
- WebSocket:双向实时通信,客户端和服务端都要主动发消息
- SSE:服务端单向推送,客户端主要负责监听
- HTTP/2:更偏向协议层能力和服务器推送,不是实时交互的默认入口
如果你的目标只是客户端接收事件流,先看 SSE 客户端教程。
如果你的目标是聊天室、协作或实时控制,先看 连接第一个 WebSocket 服务。
WebSocket:把 HTTP 请求升级成双向连接
Section titled “WebSocket:把 HTTP 请求升级成双向连接”这是最常见的协议升级场景。
服务端核心写法就是在请求里调用 upgrade(new WebSocketUpgrade()):
import tech.smartboot.feat.Feat;import tech.smartboot.feat.core.server.WebSocketRequest;import tech.smartboot.feat.core.server.WebSocketResponse;import tech.smartboot.feat.core.server.upgrade.websocket.WebSocketUpgrade;
public class WebSocketDemo { public static void main(String[] args) { Feat.httpServer().httpHandler(request -> { request.upgrade(new WebSocketUpgrade() { @Override public void handleTextMessage(WebSocketRequest request, WebSocketResponse response, String message) { response.sendTextMessage("接受到客户端消息:" + message); } }); }).listen(); }}这段代码表达的其实很简单:
- 客户端先发一个普通 HTTP 请求
- 服务端决定把它升级成 WebSocket
- 升级成功后,后续处理就进入 WebSocket 消息收发模型
仓库里的完整示例见:
SSE:把 HTTP 请求升级成事件流
Section titled “SSE:把 HTTP 请求升级成事件流”SSE 更适合“服务端持续发、客户端被动收”的模式。
在 Feat 里它的写法同样是一次升级,只是升级目标换成了 SSEUpgrade。
import tech.smartboot.feat.Feat;import tech.smartboot.feat.core.server.upgrade.sse.SSEUpgrade;import tech.smartboot.feat.core.server.upgrade.sse.SseEmitter;
import java.io.IOException;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;
public class SSEDemo { public static void main(String[] args) { Feat.httpServer(serverOptions -> serverOptions.debug(true)) .httpHandler(req -> { req.upgrade(new SSEUpgrade() { public void onOpen(SseEmitter sseEmitter) { Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() { int i = 0;
@Override public void run() { try { sseEmitter.send( SseEmitter.event() .name("update") .comment("aaa") .id(String.valueOf(i++)) .data("hello world") ); if (i == 10) { sseEmitter.complete(); } } catch (IOException e) { throw new RuntimeException(e); } } }, 1, 1, TimeUnit.SECONDS); } }); }).listen(8080); }}这更适合:
- 日志流
- 通知流
- 状态更新流
- 构建输出流
HTTP/2:更偏协议层能力,而不是默认业务入口
Section titled “HTTP/2:更偏协议层能力,而不是默认业务入口”和 WebSocket、SSE 不同,HTTP/2 不一定意味着你要做一个“实时消息协议”。
很多时候你更关心的是:
- 多路复用
- 头部压缩
- 服务器推送
如果你确实要自己处理 HTTP/2 升级流程,仓库里也有对应示例:
import org.smartboot.socket.extension.plugins.SslPlugin;import org.smartboot.socket.extension.plugins.StreamMonitorPlugin;import org.smartboot.socket.extension.ssl.factory.AutoServerSSLContextFactory;import tech.smartboot.feat.core.common.HeaderValue;import tech.smartboot.feat.core.server.HttpRequest;import tech.smartboot.feat.core.server.HttpResponse;import tech.smartboot.feat.core.server.HttpServer;import tech.smartboot.feat.core.server.PushBuilder;import tech.smartboot.feat.core.server.upgrade.http2.Http2Upgrade;
import javax.net.ssl.SSLEngine;import javax.net.ssl.SSLParameters;import java.util.function.Consumer;
public class Http2Demo { public static void main(String[] args) throws Exception { HttpServer bootstrap = new HttpServer(); bootstrap.httpHandler(request -> request.upgrade(new Http2Upgrade() { @Override public void handle(HttpRequest request) throws Throwable { HttpResponse response = request.getResponse(); PushBuilder pushBuilder = request.newPushBuilder(); if (pushBuilder != null) { request.newPushBuilder().path("/aa.css").addHeader("aa", "bb").method("GET").push(); } response.write("<html><body>hello feat</body></html>".getBytes()); } }));
SslPlugin sslPlugin = new SslPlugin(new AutoServerSSLContextFactory(), (Consumer<SSLEngine>) sslEngine -> { SSLParameters sslParameters = new SSLParameters(); sslEngine.setUseClientMode(false); sslParameters.setApplicationProtocols(new String[]{HeaderValue.Upgrade.H2}); sslEngine.setSSLParameters(sslParameters); HttpRequest.SSL_ENGINE_THREAD_LOCAL.set(sslEngine); });
bootstrap.options() .addPlugin(sslPlugin) .addPlugin(new StreamMonitorPlugin<>()) .debug(true); bootstrap.listen(8080); }}但从日常业务角度,这通常不是你使用 Feat 的第一个升级场景。
绝大多数团队会先用 WebSocket 或 SSE,只有在明确需要 HTTP/2 特性时才会深入到这层。
选 WebSocket,如果:
Section titled “选 WebSocket,如果:”- 双向通信是必须的
- 客户端不仅接收,还要频繁主动发消息
- 你在做聊天室、实时协作、游戏、控制面板
选 SSE,如果:
Section titled “选 SSE,如果:”- 主要是服务端向客户端持续推送
- 客户端不需要复杂双向通信
- 你更希望保持 HTTP 语义简单
看 HTTP/2,如果:
Section titled “看 HTTP/2,如果:”- 你真的要用服务器推送
- 你在关注协议层性能和连接模型
- 你已经知道自己为什么不是用 WebSocket / SSE
- 要看客户端怎么接收 WebSocket:去 连接第一个 WebSocket 服务
- 要看客户端怎么接收 SSE:去 SSE 客户端教程
- 如果你其实还没写过最基本的服务:先回到 构建第一个 Feat HTTP 服务