SpacetimeDB 连接拒绝机制实战:在 client_connected 阶段断开客户端接入

SpacetimeDB 连接拒绝机制实战:在 client_connected 阶段断开客户端接入 SpacetimeDB 连接拒绝机制实战在 client_connected 阶段断开客户端接入【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDBSpacetimeDB 提供了在客户端连接过程中直接拒绝接入的能力只要在client_connectedC# 中为ClientConnected生命周期 reducer 中返回错误或抛出异常该次连接就会被服务端主动断开。本篇指南以官方文档为核心结合仓库源码与冒烟测试用例讲解如何在 Rust 与 C# 服务端模块中实现连接拒绝、各语言客户端的行为差异以及服务端底层如何将 reducer 的错误映射为 HTTP 403 并中止连接生命周期。连接生命周期与 client_connected reducerSpacetimeDB 的模块可以定义三类生命周期 reducerinit、client_connected与client_disconnected每个模块每类只能定义一个且它们不能被客户端手动调用参数只能是ReducerContext。其中client_connected在客户端建立连接时运行客户端身份可以通过ReducerContext的 sender 值获取参见 crates/bindings/src/lib.rs 中的文档说明若 reducer 执行出错客户端将被断开连接If an error occurs in the reducer, the client will be disconnected。这一点正是“连接拒绝”机制的核心client_connected不仅是连接成功的回调更是服务端决定是否接受该连接的校验点。Rust 服务端从 client_connected 返回错误以拒绝连接在 Rust 服务端模块中将client_connectedreducer 的返回类型声明为Result(), String并在需要拒绝时返回Err即可。以下示例对所有入站连接一律拒绝#[reducer(client_connected)] pub fn client_connected(_ctx: ReducerContext) - Result(), String { let client_is_rejected true; if client_is_rejected { Err(The client connection was rejected. With our current code logic, all clients will be rejected..to_string()) } else { Ok(()) } }要点说明返回Ok(())表示接受连接Err(msg)表示拒绝panic 同样会导致连接被断开。在真实业务中client_is_rejected通常替换为基于ctx.sender()的身份校验、IP 校验或业务逻辑判断从而实现只拒绝特定客户端的策略。仓库中的冒烟测试模块 crates/smoketests/modules/client-connection-reject/src/lib.rs 提供了完整可验证的写法init填充数据表client_connected恒定返回Err(Rejecting connection from client.to_string())并在client_disconnected中panic!断言该回调不应被触发因为连接从未被接受#[spacetimedb::reducer(client_connected)] pub fn identity_connected(_ctx: ReducerContext) - Result(), String { Err(Rejecting connection from client.to_string()) } #[spacetimedb::reducer(client_disconnected)] pub fn identity_disconnected(_ctx: ReducerContext) { panic!(This should never be called, since we reject all connections!) }此外modules/sdk-test-connect-disconnect/src/lib.rs 展示了正常的连接生命周期client_connected将客户端身份写入connected表、client_disconnected写入disconnected表用于验证“连接成功→断开→重连”的全流程可作为对比理解拒绝场景的基线。C# 服务端在 ClientConnected 中抛出异常以拒绝连接在 C# 服务端模块中连接拒绝的实现方式是让ClientConnectedreducer 抛出异常。以下示例对所有入站连接一律拒绝[Reducer(ReducerKind.ClientConnected)] // Called when a client connects to a SpacetimeDB database server public static void ClientConnected(ReducerContext ctx) { throw new Exception(The client connection was rejected. With our current code logic, all clients will be rejected.); }仓库中的回归测试 sdks/csharp/examples~/regression-tests/server/Lib.cs 也使用相同的[Reducer(ReducerKind.ClientConnected)]属性标记方式确认了该 API 的实际用法。各语言客户端的断开行为差异连接被拒绝后客户端的可观测行为因 SDK 语言而异官方文档记录如下客户端类型断开行为表现C# 客户端断开行为当前未定义会收到错误Disconnected abnormally: System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake.Rust 客户端服务端为 Rust断开行为当前未定义会收到错误Unable to send subscribe message: WS sender loop has dropped its recv channel: TrySendError { kind: Disconnected }Rust 客户端服务端为 C#收到on_disconnected事件且无错误消息TypeScript 客户端收到Error connecting to SpacetimeDB:与 code 为 1006 的CloseEventWebSocket 非正常关闭的标准化错误码TypeScript SDK 中的 sdks/typescript/src/sdk/db_connection_impl.ts 正是通过stdbLogger(error, Error connecting to SpacetimeDB WS)输出这一错误前缀印证了文档描述。对服务端而言无论客户端类型如何连接都会被断开且模块日志中会记录相应错误条目C# 服务端日志ERROR: : System.Exception: The client connection was rejected. With our current code logic, all clients will be rejected.Rust 服务端日志ERROR: : The client connection was rejected. With our current code logic, all clients will be rejected.服务端底层实现reducer 错误如何映射为连接拒绝从服务端源码可以深入理解“返回错误即拒绝连接”的底层链路。在 crates/client-api/src/routes/database.rs 的with_connection函数中每个 HTTP 客户端连接的生命周期是这样执行的生成随机的connection_id调用模块的client_connectedreducer即module.call_identity_connected(...)若该调用返回错误则在执行后续fut之前直接终止连接生命周期即告结束只有连接被接受后才执行订阅、SQL 等后续操作并在结束时调用call_identity_disconnected收尾即使后续执行失败也会断开保证client_disconnected始终运行。错误到 HTTP 响应的映射逻辑见client_connected_error_to_responsecrates/client-api/src/routes/database.rs共四种情形错误类型HTTP 状态码含义Rejected(msg)403 Forbiddenclient_connectedreducer 返回错误连接被拒绝响应体携带拒绝消息OutOfEnergy503 Service Unavailable数据库能量预算耗尽ReducerCall(e)404 Not Found调用client_connected时发生异常DBError(_)500 Internal Server Error模块未定义client_connected但插入st_client表时出错可见连接拒绝并非简单的 WebSocket 断开而是服务端以403 Forbidden语义化地终止连接生命周期这正是“断开客户端连接”在协议层面的落地方式。实战要点与最佳实践拒绝路径上不要依赖 client_disconnected连接被拒绝时client_connected之后的流程不会执行client_disconnected也不会按正常路径触发如 client-connection-reject 模块的断言所示。因此不要在拒绝场景下假设断开回调必然运行。利用拒绝做接入控制将Err消息替换为具体的拒绝原因可以做到按身份ctx.sender()、按时间、按配额等策略拒绝同时错误信息会同步出现在服务端日志中便于排查。客户端应处理非正常关闭TypeScript 客户端收到 code 1006 的CloseEvent、C# 客户端可能收到 WebSocket 握手异常均属于非优雅关闭客户端侧需将其识别为“连接被拒绝”并给出明确提示而不是依赖 close handshake 的完成。测试验证可参考 crates/smoketests/modules/client-connection-reject/src/lib.rs 与 crates/smoketests/modules/client-connection-http-cancel/src/lib.rs 等冒烟测试模块搭建可重复验证的连接拒绝场景。【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考