Skip to content

在 Feat 中使用协议升级

This content is not available in your language yet.

在 Feat 里,协议升级的意义不是“多学一个 API”,而是让同一个 HTTP 服务入口可以承接不同的实时通信模式。
这页的重点不是讲协议标准,而是回答:什么时候该用哪种升级方式,以及在 Feat 里怎么落地。

如果你现在只是知道“我要实时通信”,先不要急着写代码。先判断是哪一类:

  • WebSocket:双向实时通信,客户端和服务端都要主动发消息
  • SSE:服务端单向推送,客户端主要负责监听
  • HTTP/2:更偏向协议层能力和服务器推送,不是实时交互的默认入口

如果你的目标只是客户端接收事件流,先看 SSE 客户端教程
如果你的目标是聊天室、协作或实时控制,先看 连接第一个 WebSocket 服务

WebSocket:把 HTTP 请求升级成双向连接

Section titled “WebSocket:把 HTTP 请求升级成双向连接”

这是最常见的协议升级场景。
服务端核心写法就是在请求里调用 upgrade(new WebSocketUpgrade())

WebSocketDemo.java
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 更适合“服务端持续发、客户端被动收”的模式。
在 Feat 里它的写法同样是一次升级,只是升级目标换成了 SSEUpgrade

SSEDemo.java
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 升级流程,仓库里也有对应示例:

Http2Demo.java
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 特性时才会深入到这层。

  • 双向通信是必须的
  • 客户端不仅接收,还要频繁主动发消息
  • 你在做聊天室、实时协作、游戏、控制面板
  • 主要是服务端向客户端持续推送
  • 客户端不需要复杂双向通信
  • 你更希望保持 HTTP 语义简单
  • 你真的要用服务器推送
  • 你在关注协议层性能和连接模型
  • 你已经知道自己为什么不是用 WebSocket / SSE