WebSocket
2025/3/9大约 1 分钟hyperlanewebrustusage-introductionwebsocket
提示
hyperlane 框架支持 websocket 协议,服务端自动处理协议升级,支持请求中间件,路由处理,响应中间件。
服务端代码
提示
hyperlane 框架发送 websocket 响应使用 stream.try_send_list 发送帧列表。 由于 websocket 协议基于 http,所以可以像使用 http 一样处理请求, 但是需要注意响应数据需要通过 WebSocketFrame::create_frame_list 进行帧处理。 对于 websocket 响应,请统一使用 stream.try_send_list 或 stream.try_send 方法。
单点发送
struct WebsocketRoute;
impl WebsocketRoute {
async fn try_send_body_hook(
&self,
stream: &mut Stream,
ctx: &mut Context,
) -> Result<(), ResponseError> {
let send_result: Result<(), ResponseError> = if ctx.get_request().is_ws_upgrade_type() {
let body: &ResponseBody = ctx.get_response().get_body();
let frame_list: Vec<ResponseBody> = WebSocketFrame::create_frame_list(body);
stream.try_send_list(&frame_list).await
} else {
let body: &Vec<u8> = ctx.get_response().get_body();
stream.try_send(body).await
};
if send_result.is_err() {
stream.set_closed(true);
}
send_result
}
}
impl ServerHook for WebsocketRoute {
async fn new(_: &mut Stream, _: &mut Context) -> Self {
Self
}
async fn handle(self, stream: &mut Stream, ctx: &mut Context) -> Status {
while let Ok(body) = stream.try_get_websocket_request().await {
ctx.get_mut_response().set_body(body);
if self.try_send_body_hook(stream, ctx).await.is_err() {
return Status::Reject;
}
}
Status::Continue
}
}属性宏写法
提示
可以使用 #[is_ws_upgrade_type] 和 #[try_get_websocket_request] 属性宏简化 WebSocket 处理。
use hyperlane::*;
use hyperlane_macros::*;
#[route("/ws_upgrade_type")]
struct Websocket;
impl ServerHook for Websocket {
async fn new(_: &mut Stream, _: &mut Context) -> Self {
Self
}
#[is_ws_upgrade_type]
#[try_get_websocket_request(body)]
async fn handle(self, stream: &mut Stream, ctx: &mut Context) -> Status {
let body_list: Vec<ResponseBody> = WebSocketFrame::create_frame_list(&body);
stream.send_list(body_list).await;
Status::Continue
}
}广播发送
提示
需要阻塞住当前处理函数,将后续所有请求在处理函数中处理。 这里使用 tokio 的 select 来处理多个请求,使用 hyperlane-broadcast 来实现广播。
客户端代码
const ws = new WebSocket('ws://localhost:60000/websocket');
ws.onopen = () => {
console.log('WebSocket opened');
setInterval(() => {
ws.send(`Now time: ${new Date().toISOString()}`);
}, 1000);
};
ws.onmessage = (event) => {
console.log('Receive: ', event.data);
};
ws.onerror = (error) => {
console.error('WebSocket error: ', error);
};
ws.onclose = () => {
console.log('WebSocket closed');
};