简介
silky 框架通过 WebSocketSharp 支持微服务应用提供 WebSocket 通信能力。silky 网关实现了 WebSocket 代理中间件,前端可以通过网关地址与 WebSocket 服务建立会话。
工作原理:
- 客户端通过网关 WebSocket 地址(
ws://gateway/api/wsservice?hashkey=xxx)发起握手 - 网关通过
hashkey参数使用哈希算法路由到固定的 WebSocket 服务实例 hashkey与SessionId的对应关系缓存在BusinessSessionIds字典中- 其他微服务可调用 WebSocket 服务的接口方法,通过
SessionManager向指定客户端推送消息
构建支持 WebSocket 通信的主机
使用 ConfigureSilkyWebSocketDefaults() 构建 WebSocket 主机(推荐方式):
using Microsoft.Extensions.Hosting;
var hostBuilder = Host.CreateDefaultBuilder(args)
.ConfigureSilkyWebSocketDefaults();
await hostBuilder.Build().RunAsync();
或使用自定义启动模块(继承 WebSocketHostModule):
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureSilkyWebSocket<CustomWsHostModule>();
定义和实现 WebSocket 服务
定义应用服务接口
WebSocket 服务接口与普通应用服务接口定义相同,使用 [ServiceRoute] 标识,接口方法可以与其他微服务通过 RPC 通信,也可以承载向 WebSocket 客户端推送消息的逻辑:
[ServiceRoute]
public interface IWsTestAppService
{
/// <summary>
/// 向指定 businessId 的 WebSocket 客户端推送消息
/// </summary>
Task Echo(string businessId, string msg);
}
实现应用服务
实现类需要同时继承 WsAppServiceBase 基类(提供 WebSocket 会话管理能力):
public class WsTestAppService : WsAppServiceBase, IWsTestAppService
{
private readonly ILogger<WsTestAppService> _logger;
public WsTestAppService(ILogger<WsTestAppService> logger)
{
_logger = logger;
}
// 建立 WebSocket 会话时触发
protected override void OnOpen()
{
base.OnOpen();
_logger.LogInformation("WebSocket session established, SessionId: {SessionId}", ID);
}
// 收到客户端消息时触发
protected override void OnMessage(MessageEventArgs e)
{
_logger.LogInformation("Received message: {Message}", e.Data);
// 向当前客户端回送消息
Send($"Echo: {e.Data}");
}
// 会话关闭时触发
protected override void OnClose(CloseEventArgs e)
{
base.OnClose(e);
_logger.LogInformation("WebSocket session closed, reason: {Reason}", e.Reason);
}
// 由其他微服务通过 RPC 调用,向指定客户端推送消息
public async Task Echo(string businessId, string msg)
{
if (BusinessSessionIds.TryGetValue(businessId, out var sessionIds))
{
foreach (var sessionId in sessionIds)
{
SessionManager.SendTo($"[Server Push] {msg}", sessionId);
}
}
else
{
throw new BusinessException($"不存在 businessId 为 {businessId} 的 WebSocket 会话");
}
}
}
关键属性说明:
| 属性/方法 | 说明 |
|---|---|
ID | 当前 WebSocket 会话的 SessionId |
BusinessSessionIds | hashkey → SessionId[] 的字典,记录所有已建立的会话映射 |
SessionManager.SendTo(msg, sessionId) | 向指定 SessionId 的客户端推送消息 |
Send(msg) | 向当前客户端发送消息(在 OnMessage 中使用) |
网关配置 WebSocket 代理
在网关的 Startup.Configure 中启用 WebSocket 代理中间件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ... 其他中间件
app.UseRouting();
app.UseSilkyWebSocketsProxy(); // WebSocket 代理中间件(必须在 UseEndpoints 之前)
app.UseEndpoints(endpoints =>
{
endpoints.MapSilkyRpcServices();
});
}
注意
WebSocket 服务对应的网关只能部署一个实例,以确保客户端每次都路由到同一个 WebSocket 服务实例(hashkey 哈希路由的前提)。
客户端建立 WebSocket 会话
客户端通过网关地址与 WebSocket 服务建立会话,连接格式:
ws://gateway_host:port/api/{serviceName}?hashkey={businessId}
必须通过 querystring 参数或请求头传入 hashkey(即 businessId),否则无法建立会话。
示例(以上述 WsTestAppService 为例):
ws://127.0.0.1:5000/api/wstest?hashkey=user_100
连接建立后效果:

通过调用 WebAPI 触发服务端向 WebSocket 客户端推送消息:

WebSocket 客户端接收到服务端推送的消息:

如果指定 hashkey 对应的会话不存在,则抛出异常:

