
























| 问题 | 答案 |
|---|---|
| 是否需要 Hub 返回 Cookie? | ❌ 不需要 |
| Cookie 由谁生成? | ✅ Ocelot 网关 |
| Cookie 值是什么? | ✅ Ocelot 生成的随机 GUID |
| 实例标识来源? | ✅ Consul 返回的 Host:Port |
| 下游服务是否感知? | ❌ 完全无感知 |
| SignalR 是否还需要 Redis? | ✅ 多实例广播仍需 |
Ocelot 的 CookieStickySessions 负载均衡器在网关层完全接管了会话亲和性,其执行流程如下:
ServiceName 对应的健康实例列表(如 192.168.1.10:5000, 192.168.1.11:5000)。192.168.1.10:5000)。abc123),并在内存字典中建立映射:{ "abc123" -> "192.168.1.10:5000" }。Set-Cookie: Ocelot_SignalR_Affinity=abc123。/negotiate 和 WebSocket 升级落在同一台机器。关键点:Cookie 的值是 Ocelot 的随机 Key,绑定的目标是 Consul 的具体节点地址,而非服务名。
{
"Routes": [
{
"UpstreamPathTemplate": "/hubs/chat/{*any}",
"UpstreamHttpMethod": ["Get", "Post", "Put", "Delete"],
"DownstreamPathTemplate": "/hubs/chat/{*any}",
"DownstreamScheme": "http",
"ServiceName": "signalr-service",
"LoadBalancerOptions": {
"Type": "CookieStickySessions",
"Key": "Ocelot_SignalR_Affinity",
"Expiry": 3600000
}
}
],
"GlobalConfiguration": {
"ServiceDiscoveryProvider": {
"Scheme": "http",
"Host": "consul",
"Port": 8500,
"Type": "Consul"
},
"BaseUrl": "http://localhost:5000"
}
}
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOcelot();
var app = builder.Build();
app.UseWebSockets(); // 必须启用 WebSocket
await app.UseOcelot();
app.Run();
⚠️ 必须配置 withCredentials: true,否则浏览器不会保存/发送网关下发的 Cookie。
const connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:5000/hubs/chat", {
withCredentials: true
})
.withAutomaticReconnect()
.build();
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.error(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => { await start(); });
start();
即使有了 Sticky Session,为了跨实例广播消息,仍需配置 Redis。
// Program.cs of SignalR Service
builder.Services.AddSignalR()
.AddStackExchangeRedis("redis:6379", options =>
{
options.Configuration.ChannelPrefix = "MyApp:SignalR";
});
确保 Consul 中注册的地址是 Ocelot 能直接访问的 IP 或容器名。
{
"ID": "signalr-node-1",
"Name": "signalr-service",
"Address": "signalr-svc-1",
"Port": 5000,
"Check": {
"HTTP": "http://signalr-svc-1:5000/health",
"Interval": "10s"
}
}
| 场景 | 说明 |
|---|---|
| Ocelot 多实例部署 | ⚠️ Ocelot 的粘性字典存在本机内存,若前面有 LB,需在 Nginx/K8s 再做一层 Sticky。 |
| 跨域 (CORS) | 网关和 SignalR 服务必须配置 AllowCredentials(),且不能设置 AllowAnyOrigin()。 |
| 实例重启/下线 | 若 Consul 摘除实例,Ocelot 内存映射失效,客户端需重连并获取新 Cookie。 |
| LongPolling | 同样依赖 Cookie 粘性,确保每次轮询请求都带上 Cookie。 |
| Docker/K8s | 确保 DownstreamHostAndPorts 或 Consul 注册的是容器网络可达地址。 |
SignalR 的会话粘性完全由 Ocelot 网关通过
Set-Cookie实现,基于 Consul 返回的具体实例地址进行绑定,Hub 无需编写任何 Cookie 逻辑,只需配合 Redis Backplane 即可在微服务下稳定运行。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。