15 · WebSocket(ace-websocket)
WebSocket 是独立可插拔组件 ace-websocket(不在核心,对标 Spring Boot 的 spring-boot-starter-websocket)。注解驱动,风格对标 JSR 356(Jakarta WebSocket)的 @ServerEndpoint/@OnMessage。
引入
cjpm.toml 加依赖,main 所在文件 import 触发自注册:
[dependencies]
"aceboot::websocket" = { path = "../../ace-websocket" }
import aceboot::websocket.* // WsSession;@WsController 等宏在 aceboot::framework_macros
声明式端点
@WsController["/ws/chat/:room"] // 路径支持 :param(复用 path-to-regexp)
public class ChatSocket {
@OnOpen
public func onOpen(session: WsSession): Unit {
session.send("welcome")
}
@OnMessage
public func onMessage(message: String, session: WsSession): Unit {
session.send("echo: ${message}") // 主动回发
}
@OnClose
public func onClose(session: WsSession): Unit { ... }
}
@WsController["/path"]— 端点类 + 路径(对标@ServerEndpoint)。@OnOpen func onOpen(session: WsSession)— 连接建立。@OnMessage func onMessage(message: String, session: WsSession)— 收到文本消息(签名固定为(String, WsSession))。@OnClose func onClose(session: WsSession)— 连接关闭。@OnError func onError(session: WsSession, error: Exception)— 帧循环异常。- 三个回调均可选;端点类是单例 Bean,可
@Inject其它服务。
WsSession:
session.send(text: String) // 发送文本帧
session.sendBytes(data: Array<UInt8>) // 发送二进制帧
session.close() // 主动关闭(Close 帧)
机制与分层
带 Upgrade: websocket 的请求
→ ace-http dispatch 在「构造 Context / 读 body / 跑洋葱」之前分流
→ 匹配 @WsController 端点(path-to-regexp)→ stdx WebSocket.upgradeFromServer 握手
→ 帧循环:文本帧 → @OnMessage;Ping 自动回 Pong;Close → 退出 → @OnClose
- 独立组件:
ace-websocket单向依赖ace-http,启动期经registerWsEndpoint把端点「推」给 ace-http 注册表(依赖倒置,ace-http 不反依赖 ace-websocket,核心 ace-web/router 不含 ws)。 - 底层:stdx
WebSocket(upgradeFromServer自动完成 101 握手 +Sec-WebSocket-Accept,read()/write()收发帧)。 - 每连接一协程跑帧循环(契合 stdx 服务端模型)。
限制
- WebSocket 升级在洋葱之前分流,故不经认证/中间件。需要鉴权请在
@OnOpen内自行校验(v1WsSession暂未暴露握手请求头,后续可加)。 @OnMessage仅触发文本帧;二进制帧/分片的高层回调待后续。
测试
import asyncio, websockets
async def main():
async with websockets.connect("ws://127.0.0.1:8080/ws/chat/room1") as ws:
print(await ws.recv()) # welcome
await ws.send("hi"); print(await ws.recv()) # echo: hi
asyncio.run(main())
回到 文档导航。