ASP.NET SignalR 系列(八)之跨域推送

前面几章讲的都是同域下的推送和订阅。这种讲讲如何跨域

对于SignalR来说,默认是不允许跨域的,因为安全问题。虽如此,但同时提供了跨域方案。

两种跨域方式:

1:JSONP
2:CORS

JSONP的方式比Cors更不安全。下面分别讲讲怎么使用

一、JSONP方式

服务端设置:

Startup.cs文件
public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            //JSONP方式
            app.MapSignalR(new HubConfiguration() {EnableJSONP = true});
        }
    }

然后在全局文件中Global.cs注册,允许jsonp

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);

            //注册为允许跨域,JSONP模式需要
            var config = new HubConfiguration();
            config.EnableJSONP = true;
     
        }
    }

 

前端:在其他项目中新建一个html文件

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <link href="/Content/bootstrap.min.css" rel="stylesheet" />
    <script src="/Scripts/jquery-1.10.2.min.js"></script>
    <script src="http://localhost:59831/Scripts/jquery.signalR-2.3.0.min.js"></script>
    <script src="http://localhost:59831/signalr/hub/hubs"></script>   <!--指向集线器服务器-->
    <meta charset="utf-8" />
    <style type="text/css">
        body {
            margin: 20px;
        }

        .input {
            padding-left: 5px;
        }
    </style>
</head>
<body>
    <div>
        <h4>这是跨域的页面</h4>
        <hr />
        <p>
            <input type="text" id="content" placeholder="发送内容" class="input" />&nbsp;&nbsp;<input type="button" value="发送" class="btn btn-sm btn-info" id="btn_send" />
        </p>

        <div>
            <h4>接收到的信息:</h4>
            <ul id="dataContainer"></ul>
        </div>
    </div>

    <script language="javascript">
        $(function () {
            $.connection.hub.url = 'http://localhost:59831/signalr'; //指定signalR服务器,这个是关键,signalR为固定,系统默认。除非集线器那边重定义。
            var chat = $.connection.demoHub; //连接服务端集线器,demoHub为服务端集线器名称,js上首字母须改为小写(系统默认)
            //定义客户端方法,此客户端方法必须与服务端集线器中的方法名称、参数均一致。
            //实际上是服务端调用了前端的js方法(订阅)
            chat.client.show = function (content) {
                var html = '<li>' + htmlEncode(content) + "</li>";
                $("#dataContainer").append(html);
            }

            //定义推送,跨域启动时,必须指定 jsonp:true
            $.connection.hub.start({ jsonp: true })
                .done(function () {
                    $("#btn_send").click(function () {
                        chat.server.hello($("#content").val());  //将客户端的content内容发送到服务端
                        $("#content").val("");
                    });
                });
        });
        //编码
        function htmlEncode(value) {
            var encodedValue = $('<div />').text(value).html();
            return encodedValue;
        }
    </script>
</body>
</html>

 

上效果图:

 

 

从上图可以看到,用到的域名不同,一个端口号59831 ,一个61625。实现了跨域

 

第二种:Cors 模式

该模式需要下载Microsoft.Owin.Cors组件,可从Nuget中获取

安装完成后,注册Strartup.cs文件

 public void Configuration(IAppBuilder app)
        {
            ////系统默认
            //app.MapSignalR();
            //JSONP方式
            //app.MapSignalR(new HubConfiguration() {EnableJSONP = true});

            //Cors跨域模式
            app.Map("/signalr", map =>
            {
                // Setup the CORS middleware to run before SignalR.
                // By default this will allow all origins. You can 
                // configure the set of origins and/or http verbs by
                // providing a cors options with a different policy.
                map.UseCors(CorsOptions.AllowAll);
                var hubConfiguration = new HubConfiguration
                {
                    // You can enable JSONP by uncommenting line below.
                    // JSONP requests are insecure but some older browsers (and some
                    // versions of IE) require JSONP to work cross domain
                    // EnableJSONP = true
                };
                // Run the SignalR pipeline. We're not using MapSignalR
                // since this branch already runs under the "/signalr"
                // path.
                map.RunSignalR(hubConfiguration);
            });
        }

如果需要同时兼容 JSONP,那么将上面EnableJSONP = true 注释取消即可。

cors模式,不需要再global中注册了,如果要兼容JSONP,那么注册还是需要保留

 

下面上前端:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <link href="/Content/bootstrap.min.css" rel="stylesheet" />
    <script src="/Scripts/jquery-1.10.2.min.js"></script>
    <script src="http://localhost:59831/Scripts/jquery.signalR-2.3.0.min.js"></script>
    <script src="http://localhost:59831/signalr/hub/hubs"></script>  
    <meta charset="utf-8" />
    <style type="text/css">
        body {
            margin: 20px;
        }

        .input {
            padding-left: 5px;
        }
    </style>
</head>
<body>
    <div>
        <h4>这是跨域的页面</h4>
        <hr />
        <p>
            <input type="text" id="content" placeholder="发送内容" class="input" />&nbsp;&nbsp;<input type="button" value="发送" class="btn btn-sm btn-info" id="btn_send" />
        </p>

        <div>
            <h4>接收到的信息:</h4>
            <ul id="dataContainer"></ul>
        </div>
    </div>

    <script language="javascript">
        $(function () {
            $.connection.hub.url = 'http://localhost:59831/signalr'; //指定signalR服务器
            jQuery.support.cors = true; //Cors模式必须设置
            var chat = $.connection.demoHub; //连接服务端集线器,demoHub为服务端集线器名称,js上首字母须改为小写(系统默认)
            //定义客户端方法,此客户端方法必须与服务端集线器中的方法名称、参数均一致。
            //实际上是服务端调用了前端的js方法(订阅)
            chat.client.show = function (content) {
                var html = '<li>' + htmlEncode(content) + "</li>";
                $("#dataContainer").append(html);
            }

            //定义推送,启动时无需再设置jsonp:true
            $.connection.hub.start()  
                .done(function () {
                    $("#btn_send").click(function () {
                        chat.server.hello($("#content").val());  //将客户端的content内容发送到服务端
                        $("#content").val("");
                    });
                });
        });
        //编码
        function htmlEncode(value) {
            var encodedValue = $('<div />').text(value).html();
            return encodedValue;
        }
    </script>
</body>
</html>

效果如下图:

 

至此,两种跨域模式均讲解完成。


cors相对来说安全性比较高,但是对客户端要求比较高,比如低版本的IE不支持。
JSONP的模式安全性较低,但是对低版本IE兼容比较好。
所以再使用的时候,根据实际情况做选择,或者同时兼容。

 

posted @ 2018-08-31 11:58  黄明辉  阅读(1821)  评论(0编辑  收藏  举报