文章索引
- 系列开篇
- SignalR 部分核心原理
- WebSocket部署问题和优化若干问题
- 身份验证和授权
- 服务端主动推送
- SignalR JavaScript 客户端
- AngularJS 应用
- 异常处理
想要了解SignalR得先了解WebSocket,因为大可直接说SignalR的实现是为了实现类似WebSocket的实时通信。
什么是WebSocket
它的目标是为了让浏览器和服务端双向通信,即我们可以按传统请求-接收或服务端主动发送数据给客户端。WebSocket他并非是一个功能型东西,是一种协议,得要明白这一点,但凡浏览器和服务器实现这种协议,就可以直接在任何浏览器、平台(Win/Linux等等)上实现WebSocket。
在WebSocket协议中规定,浏览器和服务器只需要一次握手,然后彼此之间就有了爱意、可以相互抛媚眼。因此这种规范带来两大优点:
- Header 极少,2字节。不言而喻,极大减少宽带。
- Server Push即服务端可以主动推送。
WebSocket 目前在浏览器上支持情况,可以参考测试页。
另一种服务器推技术:Comet
如同WebSocket的Server Push一样。对于客户端而言有两种方式:
一是基于套接口,这需要运用像Flash XMLSocket或Java Applet套接口。
二是基于HTTP长连接,而实现这一技术有三种:AJAX长轮询、iframe、htmlfile流方式。
Comet是一种兼容性很好,像很多新浪微博、QQ邮箱、GTALK等等都使用该技术。可以参考这篇文章具体实现方案。
SignalR
应该说SignalR是上种两种的一个结合,甚至支持更多方案。SignalR提供四种数据传输方式,来解决浏览器兼容问题,他们默认分别按以下来判断该采用哪种方式:
- webSockets
- serverSentEvents
- longPolling
- foreverFrame 针对IE有效的一种变态做法,我没有细看。
以上四种具体实施方案百度非常多,很全,这里不再赘述。
一个完整示例
百度上已经有很多关于聊天室的示例,因为聊天室的确非常能说明SignalR的优点,而这里示例是设计一个关于消息提醒功能。
假定需求:用户登录后接收私信或系统异常报告通知及当前服务器时间。
1、首先我们可以通过NuGet很轻松安装SignalR,并在 Startup.cs
启用SignalR的支持。
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.MapSignalR(); // 启用SignalR
}
}
MapSignalR 是默认的注册SignalR入口,这里我们完全可以自定义任意对SignalR具体实现接口。比如重新定义服务器地址(默认是 /signalr
)、自定义身份证验证和授权机制等等。对于整个SignalR框架而言,他们都是采用依赖注入,换言之我们可以最大化扩展符合业务逻辑能力。
以下是将服务器地址变更为 /demo
,且禁止生成生成客户端代理脚本。
app.MapSignalR("/demo", new Microsoft.AspNet.SignalR.HubConfiguration()
{
EnableJavaScriptProxies = false
});
2、创建Hub类
为了演示需要,我分别创建 GetNow()
和 GetCount()
两个方法:
GetNow()
:任何人都可以访问,对所有连接者发送当前时间。
GetCount()
:需要登录后才可以访问,发送自己的消息数据。
[HubName("msgHub")]
public class MessageHub : Hub
{
public void GetNow()
{
Clients.All.pushNow(DateTime.Now);
}
[Authorize]
public void GetCount()
{
List<MessageItem> ls = new List<MessageItem>();
ls.Add(new MessageItem()
{
count = new Random().Next(1, 99),
title = "异常数量",
url = "/ex"
});
ls.Add(new MessageItem()
{
count = new Random().Next(1, 99),
title = "私信",
url = "/msg"
});
Clients.Caller.pushGet(ls);
}
}
[Authorize]
默认采用的是ASP.NET的验证机制通道,换句话说当网站采用Windows登录验证,那么这里的 [Authorize]
也直接采用此方式。而对于SignalR自身已经有握手Key,来保证连接安全。
而往往默认的身份验证和授权机制很难符合业务需求,所以也可以直接继承 Microsoft.AspNet.SignalR.AuthorizeAttribute
自定义授权和验证规则,这一点后面会有专门文章来说明。
当采用 [Authorize]
属性后,就可以在方法里头调用 Context.User
对象访问当前用户信息。
另外非常重要的一点:app.MapSignalR();
必须是 ConfigureAuth(app);
之前,因为我们都懂。
3、HTML代码
当开启 EnableJavaScriptProxies
时(默认就是开启),就可以享受SignalR自动生成的一个Hub客户端脚本代码。所以我需要先引入这些脚本;包括jQuery.js、jquery.signalR.js两个核心文件。
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.signalR-2.1.2.js"></script>
<script src="~/demo/hubs"></script>
<p id="J_Now"></p>
<p id="J_GetCount"></p>
其中 ~/demo/hubs
由SignalR自动生成,这里的 /demo
是指在前面变更的服务器地址。
4、启动Hub
虽然SignalR自动生成Hub客户端脚本,但此时还是需要添加一些 client
以便于服务器推送时接收数据,和启用Hub。
(function () {
var msgHub = $.connection.msgHub;
$.extend(msgHub.client, {
pushNow: function (res) {
$('#J_Now').html(res);
},
pushGet: function (res) {
$('#J_GetCount').html(JSON.stringify(res));
}
});
$.connection.hub.start().done(function () {
init();
}).fail(function () {
// 连接失败处理
});
function init() {
setInterval(function () { msgHub.server.getNow(); }, 1000); // 按理应该是由服务器直接推送,但我想留到另一节说,不要问为什么,任性。
msgHub.server.getCount().fail(function (res) {
console.log(res);
});
}
})();
每个Hub都有对应 client
和 server
,而SignalR会反射类下的所有公共方法,并把这些自动生成拼接成JavaScript放进 server
集合里头。
client
:表示由服务端推送数据时,客户端接收对象,比如:Clients.Caller.pushGet(ls);
中的 pushGet
。
server
:表示主动请求服务端的方法,比如:GetCount()
。
对于 server.getCount()
返回的是一个 promise()
对象,所以这里可以直接 done()
、fail()
来处理一些失败或成功时操作。
以上,就是一个完整的示例。
总结
SignalR 不光解决了我们多种实时通信的方案,而且兼容性非常好,这是一个相当好的项目,不久将来一定会有越来越多项目使用,甚至我们可以整个项目都采用 SignalR。这对于用户而言是极棒的体验。
发表评论