(给DotNet加星标,提升.Net技能)
转自:cgyqu
cnblogs.com/cgyqu/p/9563193.html
背景
由于要做微信小程序聊天,所以.NetFramwork版本的SignalR版本的不能用了。因为小程序里没有windows对象,导致JQuery无法使用。而Signalr的 js客户端是依赖JQuery的。
services.AddCors(options => options.AddPolicy("SignalR",
builder =>
{
builder.AllowAnyMethod() //允许任意请求方式
.AllowAnyHeader() //允许任意header
.AllowAnyOrigin() //允许任意origin
.AllowCredentials();//允许验证
//.WithOrigins(domins) //指定特定域名才能访问
}));
然后在Configure使用定义好的跨域策略
app.UseCors("SignalR");
services.AddSignalR()
.AddMessagePackProtocol()
.AddRedis(o =>
{
o.ConnectionFactory = async writer =>
{
var config = new ConfigurationOptions
{
AbortOnConnectFail = false
};
config.EndPoints.Add(IPAddress.Loopback, 0);
config.SetDefaultPorts();
var connection = await ConnectionMultiplexer.ConnectAsync(config, writer);
connection.ConnectionFailed += (_, e) =>
{
Console.WriteLine("Connection Redis failed.");
};
if (!connection.IsConnected)
{
Console.WriteLine("Connection did not connect.");
}
return connection;
};
});
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 300;
proxy_read_timeout 300;
proxy_send_timeout 300;
于是我把应用发布到本地虚拟机里,并用docker方式运行。然后把配置写进nginx配置文件里。
发现真的不能进行POST请求了,返回400。400的意是思请求异常。肯定是这个配置有问题额。于是又去交友网站找issue,果然又让我找到了。
在一个issue里面,提供的配置如下
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
于是又去看issues,果然,里面也有人问,作者也有解释。
去交友网站看看(https://github.com/aspnet/SignalR/issues/2729)
大体意思ConnectonId是服务端使用,客户端不应该使用这种不可控的方式进行通信。 可以采用Group或者User这种可控方式通信,并且也有例子给出。
这里插一句,在使用.Net Framwork版本时候,我们网站是使用ConnectionId进行通信,经常出现重连导致ConnectionId变掉,进而通信失败。
所以我也调整了下设计思路,改使用Group进行通信。
以上都搞定了,辛苦了这么久,按道理应该没问题了吧!那么发布上线!
看到这个错误,第一个反应,我的想法是难道是Redis没连接成功,所以只能单机跑?所以我就在上面Redis代码加上各种监控,发现连接成功了。代码Review了n遍代码,实在没有地方可以改了。
于是官方文档一个个过。终于发现Js可以进行以下配置
let connection = new signalR.HubConnectionBuilder()
.withUrl("/myhub", {
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets
});
.build();
private async Task<HttpConnectionContext> GetConnectionAsync(HttpContext context)
{
var connectionId = GetConnectionId(context);
if (StringValues.IsNullOrEmpty(connectionId))
{
// There's no connection ID: bad request
context.Response.StatusCode = StatusCodes.Status400BadRequest;
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Connection ID required");
return null;
}
if (!_manager.TryGetConnection(connectionId, out var connection))
{
// No connection with that ID: Not Found
context.Response.StatusCode = StatusCodes.Status404NotFound;
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("No Connection with that ID");
return null;
}
return connection;
}
这段代码啥意思呢?就是connection在本地没找到的话,就返回404!
我去,难道是代码bug?
啥意思呢?就是这不是bug,就是这么设计的。使用SignalR时,要进行会话保持,请求要一直落到同一台服务器上。这样更稳定,并且还可以实时监控客户端的情况。
于是找运维同学在负载上配置了下会话保持,再次测试,终于可以了。
总结
在此次使用SignalR的过程中,遇到了太多的坑。花了几个小时整理并记录下来,与各位进行分享。
推荐阅读
(点击标题可跳转阅读)
看完本文有收获?请转发分享给更多人
关注「DotNet」加星标,提升.Net技能