http与websocket(基于SignalR)两种协议下的跨域基于ASP.NET MVC--竹子整理
这段时间,项目涉及到移动端,这就不可避免的涉及到了跨域的问题。这是本人第一次接触跨域,有些地方的配置是有点麻烦,导致一开始的不顺。
至于websocket具体是什么意义,用途如何:请百度。
简单说就是建立一个基于互联网的实时通信。
在这里整理下这些内容,方便日后回顾。
一:介绍了WebSocket下的基于SignalR的跨域与不跨域例子
二:简单介绍了Http下的跨域问题
Ⅰ.WebSocket下的跨域
如果使用原生的方法来开发WebSocket应用,还是比较复杂的,不过好在Asp.net给我们提供了一个框架:
SignalR:
微软支持的运行在.NET平台上集客户端与服务器于一体的库。简单来说就是给我们提供了服务端的类库加上前端的JS库。
首先抛开跨域的问题,先写一个SignalR不跨域的例子:
1、NuGet来获得我们所需要的程序集:
SignalR:我们的框架
2、新建个继承于Hub的类
1 /// <summary>
2 /// 对应不跨域的方法
3 /// </summary>
4 public class ChatHub : Hub
5 {
6 public void Send(string message)
7 {
8 //接收数据,再传输到指定或全部的客户端动态方法
9 Clients.All.addNewMessageToPage(message);
10 }
11 }
3、新建个Startup类:
只需添加一句话:app.MapSignalR();
具体的完整代码在下面的Startup里都有。
4、这样我们的服务端代码就完成了,接下来就是客户端代码:
1 $(function() {
2
3 var chat = $.connection.chat;
5 $.connection.hub.start();
9 chat.addMessage = function(message){
11 alert(message);
13 }
14
15 $("#btn").click(function(){
16
17 chat.send("给服务端发送信息");
18
19 });
20
21 });
5、好了,现在来分析下客户端代码:
前面两行就是基本的猜也能猜到的获取实例,然后开启这个连接。(相当于启动线程)。第三行定义了一个函数,这个函数是与服务端的ChatHub类里的动态方法addNewMessageToPage对应的回调函数。服务端一执行动态方法,对应的客户端(这个由服务端发送时的选择有关,这里选择就是All,也就是所有的客户端)就执行对应的回调函数。
现在知道了动态方法跟回调函数是一一对应的,服务端触发动态方法,客户端执行回调函数。那么动态方法什么时候执行呢,显而易见,是客户端发送请求时,也就是这里“调用”服务端定义的Send方法时,触发了动态方法。(有点啰嗦了,为了保证人人看懂)。这样一来,最后这句 chat.send("给服务端发送信息");就很容易理解了。就是请求。
二、跨域(一)
先来从NuGet获取我们需要跨域所需的程序集:
有了前面的基础,对于SignalR也应该有了个基础的印象了,下面就来讲讲如何用SignalR实现跨域通信。
SignalR的实现机制与.NET WCF 或Remoting是相似的,都是使用远程代理来实现,在具体使用上,有两种不同目的的接口:PersistentConnection和Hub,其中PersistentConnection实现了长时间的轮询,Hub用来解决实时信息的交换问题。
先来了解一下基于PersistentConnection接口的跨域。
我们的跨域一:
1、注释掉我们Startup类中的唯一一行代码:app.MapSignalR();
然后换上我们跨域的代码:
1 //这个参数"/echo",是我们自己定义的一个路由,与客户端创建SignalR的实例时对应。
2 app.Map("/echo",
3 map =>
4 {
5 map.UseCors(CorsOptions.AllowAll);
6 map.RunSignalR<EchoConnection>();
7 }
8 );
2、新建一个类,继承于我们的接口PersistentConnection
通信的本质就是建立一个客户端与服务端的一个连接,SignalR就是我们帮助我们建立这个连接的“中间件”
这个类中就实现了接口中定义的一系列方法,如连接建立,断开连接,收到信息。这样一来,我们的chatHub类实际上就已经不起作用了,通信的方法都可以写在这个EchoConnection类中。
1 public class EchoConnection:PersistentConnection
2 {
3 /// <summary>
4 /// 当前连接数
5 /// </summary>
6 private static int _connections = 0;
7 /// <summary>
8 /// 连接建立时执行
9 /// </summary>
10 /// <param name="request"></param>
11 /// <param name="connectionId"></param>
12 /// <returns></returns>
13 protected override async Task OnConnected(IRequest request, string connectionId)
14 {
15 Interlocked.Increment(ref _connections);
16 await Connection.Send(connectionId, "Hi, " + connectionId + "!");
17 await Connection.Broadcast("新连接 " + connectionId + "开启. 当前连接数: " + _connections);
18
19 }
20 /// <summary>
21 /// 连接关闭时执行
22 /// </summary>
23 /// <param name="request"></param>
24 /// <param name="connectionId"></param>
25 /// <returns></returns>
26 protected Task OnDisconnected(IRequest request, string connectionId)
27 {
28 Interlocked.Decrement(ref _connections);
29 return Connection.Broadcast(connectionId + " 连接关闭. 当前连接数: " + _connections);
30 }
31 /// <summary>
32 /// 服务器接收到前台发送的消息时执行 发送请求 connection.send("信息");
33 /// </summary>
34 /// <param name="request"></param>
35 /// <param name="connectionId"></param>
36 /// <param name="data"></param>
37 /// <returns></returns>
38 protected override Task OnReceived(IRequest request, string connectionId, string data)
39 {
40 var message = connectionId + ">> " + data;
41 return Connection.Broadcast(message);
42 }
43
44 }
3、接下来就是客户端代码:
同样,第一步,获取实例,建立连接
var connection = $.connection("http://localhost:23013/echo");//echo就是我们之前在Startup类中定义的路由。
connection.start();
建立连接后,就会触发服务端的OnConnected事件,然后这个事件中又有触发两个方法:Broadcast,Send。这个就相当于我们不跨域时自己定义的动态方法,so,我们就应该想到客户端应有对应的回调函数:Broadcast跟Send。但是!由于这不是我们自定义的,所以,名字就不是我们想的这样啦~~对于接收信息,我们直接调用connection.received(function (data){})来接收,对于发送信息到服务端也不需要我们手动来先在服务端定义方法如不跨域时在ChatHub中定义的send方法,直接connection(实例名).send()就可以发消息到服务端。而在服务端,是由OnReceived来处理。具体的代码同样在本文的最后。
跨域(一)小结:
1 /// <summary>
2 /// 对应跨域的第一种方法
3 /// 1、前台直接用connection(实例).send()就可以发消息到服务端,用connection.received(function (data) {
4 /// $("body").append(data + "<br />");
5 /// });就能接收服务端放过来的消息
6 /// 2、后台Connection.Send(connectionId, "消息");可发送消息给指定的客户端
7 /// 用Connection.Broadcast("消息");可发送给所有的客户端
8 /// 用protected override Task OnReceived(IRequest request, string connectionId, string data)
9 /// {
10 /// var message = connectionId + ">> " + data;
11 /// return Connection.Broadcast(message);
12 /// }接收客户端发送来的消息,进行处理
13 /// </summary>
三、跨域(二)
相比PersistentConnection这种轮询机制,基于Hub利用js动态载入执行方法才是我们所说的websocket技术。
Let’s start
1、有的朋友应该知道我们的第一步都是为前端可以创建实例准备的了
再一次修改我们的Startup类,之前的注释掉:
1 app.Map("/signalr", map =>
2 {
3 map.UseCors(CorsOptions.AllowAll);
4 var hubConfiguration = new HubConfiguration
5 {
6 EnableJSONP = true//跨域的关键语句
7 };
8 map.RunSignalR(hubConfiguration);
9 });
10 app.MapSignalR();
上面的/signalR即我们这次设置的路由。一样,供客户端匹配
1、重新建立我们的MyHub类,跟最开始不跨域的步骤一致,新建类,继承于Hub。然后实现接口,里面也有连接、断开连接、重连事件。以及我们自定义的方法也都写在这里:
1 /// <summary>
2 /// 对应跨域的第二种方法
3 /// public IGroupManager Groups { get; set; } hub类中还有个组属性,尚待开发,待看文档,再写demo
4 /// </summary>
5 public class MyHub : Hub
6 {
7 /// <summary>
8 /// 连接前执行
9 /// </summary>
10 /// <returns></returns>
11 public override System.Threading.Tasks.Task OnConnected()
12 {
13 //Clients.All.sayHello("连接成功");
14 Clients.Caller.sayHello("连接成功");//当前请求的用户
15 return base.OnConnected();
16 }
17
18 /// <summary>
19 /// 断开链接时执行
20 /// </summary>
21 /// <param name="stopCalled"></param>
22 /// <returns></returns>
23 public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
24 {
25 return base.OnDisconnected(stopCalled);
26 }
27
28 /// <summary>
29 /// 重新建立连接 如服务器重启的时候,或者前台获取超时仍在等待,重连上时
30 /// </summary>
31 /// <returns></returns>
32 public override System.Threading.Tasks.Task OnReconnected()
33 {
34 return base.OnReconnected();
35 }
36
37 public void Hello(string name)//方法名称首字母大小写都与前台匹配上 前台首字母必须小写
38 {
39 //动态方法,与前台的回调函数名称一致
40 Clients.All.sayHello2("第二次");
41 Clients.All.sayHello3(Context.ConnectionId);//第三个回调函数,返回链接的ConnectionId
42 }
43 }
3、我们的客户端
第一步:获取实例,建立连接
var chat = $.connection.myHub; //获取服务端实例 首字母小写,不是跟服务端一致的MyHub chat.connection.url = "http://localhost:23013/signalr";测试项目的地址 $.connection.hub.start();
第二步、接下来就是跟服务端打个招呼
Chat.server.hello(“hello”);//对应的方法中有两个动态方法,sayHello2,sayHello3 第三步、接下来就是我们的回调函数,对应的回调函数就可以有两个,与上面对应。 chat.client.sayHello2 = function(msg) { alert(msg); }; chat.client.sayHello3 = function(msg) { alert(msg); };
WebSocket小结:基于Hub接口的跨域方法的可扩展性还是很强的,这里有几个本人总结的注意点(针对Hub跨域):
1、回调函数 函数名要匹配,参数可以不匹配,后台传过来一个就执行一个,即若后台同时触发了两个同名的sayHello 依次执行
2、一定要有回调函数,不然不算连接成功,可以不调用服务器端的方法。若只是调用服务器端方法,没写回调函数,依然不算连接成功
3、在连接成功的情况下,后台先执行OnConnected事件,再执行前台调用的某个方法
4、用回调函数来判断是否真的连接成功,$.connection.hub.start().done里直接输出连接成功,是假成功。
5、所以同样,断开连接是否成功也应用回调函数来判断,这个回调函数对应后台代码应在OnDisconnected事件里
6、第五点失败,sayGoodBye是在执行完这个事件(OnDisconnected)后才传输到前台,而事件中执行完已经把链接断开了,前台是接收不到的。
Ⅱ、HTTP下的跨域
相对于websocket协议的跨域,http应该是简单的,网上也有很多资料。这里就当笔者自己的笔记吧。
http下的跨域指异步的传输,也就是说form表单提交这种非异步方式是不存在跨域问题的。网上最多的异步跨域是jsonp方式。
Jquery跨域请求 在JavaScript中,有一个很重要的安全性限制,被称为“Same- Origin Policy”(同源策略)。这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,
即JavaScript只能访问与包含它的文档或脚本 在同一域名下的内容。不同域名下的脚本不能互相访问,即便是子域也不行。关于同源策略,读者可百度更详细的解释,这里不再赘述。
但是有时候又不可避免地需要进行跨域操作,这时候“同源策略”就是一个限制了,怎么办呢?采用JSONP跨域GET请求是一个常用的解决方案,下面我们来看一下JSONP跨域是如何实现的,
并探讨下JSONP跨域的原理。 这里提到了JSONP,那有人就问了,它同JSON有什么区别不同和区别呢,接下我们就来看看,百度百科有以下说明: JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。
JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。
易于人阅读和编写,同时也易于机器解析和生成(网络传输速度快)。
JSONP(JSON with Padding)是JSON的 一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与
不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,
而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。 到这里,应该明白了,JSON是一种轻量级的数据交换格式,像xml一样,是用来描述数据间的。JSONP是一种使用JSON数据的方式,返回的不是JSON对象,是包含JSON对象的javaScript脚本。
那JSONP是如何工作的呢,我们知道,由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。若要跨域请求出于安全性考虑是不行的,但是我们发现,
Web页面上调用js文件时则不受是否跨域的影响,而且拥有”src”这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>,这时候,聪明的程序猿就想到了变通的方法,
如果要进行跨域请求, 通过使用html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中可以直接使用JSON传递 javascript对象。即在跨域的服务端生成JSON数据,
然后包装成script脚本回传,着不就突破同源策略的限制,解决了跨域访问的问题了么。 下面我们就看下怎么实现: 前端代码: function CallWebServiceByJsonp() { $("#SubEquipmentDetails").html(''); $.ajax({ type: "GET", cache: false, url: "http://servername/webservice/webservice.asmx/GetSingleInfo", data: { strCparent: $("#Equipment_ID").val() }, dataType: "jsonp", //jsonp: "callback", jsonpCallback: "OnGetMemberSuccessByjsonp" }); } function OnGetMemberSuccessByjsonp(data) { //处理data alert(data); } 后端的WebService代码: [WebMethod] [ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet = true)] public void GetSingleInfo(string strCparent) { string ret = string.Empty; HttpContext.Current.Response.ContentType = "application/json;charset=utf-8"; string jsonCallBackFunName = HttpContext.Current.Request.Params["callback"].ToString(); //string jsonCallBackFunName1 = HttpContext.Current.Request.QueryString["callback"].Trim(); //上面代码必须 //中间代码执行自己的业务操作,可返回自己的任意信息(多数据类型) BLL.equipment eq_bll = new BLL.equipment(); List<Model.equipment> equipmentList = new List<Model.equipment>(); equipmentList = eq_bll.GetModelEquimentList(strCparent); ret = JsonConvert.SerializeObject(equipmentList); //下面代码必须 HttpContext.Current.Response.Write(string.Format("{0}({1})", jsonCallBackFunName, ret)); HttpContext.Current.Response.End(); } 如上所示,前端的CallWebServiceByJsonp方法采用jQuery的ajax方法调用后端的Web服务GetSingleInfo方法,后台的GetSingleInfo方法,
使用前端的回调方法OnGetMemberSuccessByjsonp包装后台的业务操作的JSON对象,返回给前端一段javascript片段执行。巧妙的解决了跨域访问问题。 JSONP的缺点: JSONP不提供错误处理。如果动态插入的代码正常运行,你可以得到返回,但是如果失败了,那么什么都不会发生。 链接:http://www.cnblogs.com/JerryTian/p/4194900.html
我比较喜欢下面这种简洁的方式:
$.ajax({
type:"GET",
url:"http://localhost:6874/Admin/Login/IsLegal", //跨域URL
dataType:"json",
data:{
par1:”参数1”,
par2:”参数2”
},
success:function (result){
if(result.id == "123"){
$("#div1").html("验证成功,可进行跳转");
}else{
$("#div1").html(result.name);
}
},
error:function (XMLHttpRequest, textStatus,errorThrown) { alert(errorThrown); // 调用本次AJAX请求时传递的options参数 } });
服务端代码:
1 public ActionResult IsLegal(string par1,string par2)
2 {
3 var str = new { id = "123", name = "joey" };
4
5 Httpcontext.Response.Appendheader("access-control-allow-origin", "*");
6
7 return json(str, jsonrequestbehavior.allowget);
8 }
或者定义一个特性标签,这样我们在需要跨域的action上打上特性标签即可。
public class CrossSiteAttribute : ActionFilterAttribute
{
private const string Origin = "Origin";
private const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
private const string originHeaderdefault = "*";
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
actionExecutedContext.Response.Headers.Add(AccessControlAllowOrigin, originHeaderdefault);
}
}
这样就定义了一个特性标签,[CrossSite]
使用:
[CrossSite]
public ActionResult Test()
{
return Content("跨域OK");
}
上面均是针对MVC或web api的,即对Access-Control-Allow-Origin进行了一个封装,本质都是对配置文件进行修改。所以最直接的就是配置文件修改:
webconfig中添加:
简单实用,同时可以进行post传输。
其他的跨域策略
一是通过Flash插件发送HTTP请求,这种方式可以绕过浏览器的安全限制,但必须安装Flash,并且跟Flash交互。不过Flash用起来麻烦,而且现在用得也越来越少了。
二是通过在同源域名下架设一个代理服务器来转发,JavaScript负责把请求发送到代理服务器:
'/proxy?url=http://www.sina.com.cn'
代理服务器再把结果返回,这样就遵守了浏览器的同源策略。这种方式麻烦之处在于需要服务器端额外做开发。
第三种方式称为JSONP,它有个限制,只能用GET请求,并且要求返回JavaScript。这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源:
JSONP通常以函数调用的形式返回,例如,返回JavaScript内容如下:
Foo('data')
这样一来,我们如果在页面中先准备好foo()
函数,然后给页面动态加一个<script>
节点,相当于动态读取外域的JavaScript资源,最后就等着接收回调了。
最后是之前上文一直提到的“本文最后”
1 #region 不跨域的方法
2 //app.MapSignalR();
3 #endregion
4
5 #region 跨域的第一种方法
6 //这个参数"/echo",是我们自己定义的一个路由,与客户端创建SignalR的实例时对应。
7 app.Map("/echo",
8 map =>
9 {
10 map.UseCors(CorsOptions.AllowAll);
11 map.RunSignalR<EchoConnection>();
12 }
13 );
14 #endregion
15
16 #region 第一种方法前端调用代码
17 // <script src="js/jquery-1.8.2.js"></script>
18 // <script src="js/jquery.signalR-2.2.0.min.js"></script>
19 // <script type="text/javascript">
20 // $(function () {
21 // var connection = $.connection("http://localhost:23013/echo");//对应的服务器端地址
22 // //var connection = $.connection("http://192.168.137.1/q");
23 // connection.logging = true;
24 // connection.received(function (data) {
25 // $("body").append(data + "<br />");
26 // });
27 // connection.error(function (err) {
28 // alert("存在一个错误. \n" +
29 // "Error: " + err.message);
30 // });
31 // connection.start().done(function () {
32 // $("#send").click(function () {
33 // connection.send($("#text").val());
34 // $("#text").val("").focus();
35 // });
36 // });
37 // });
38 //</script>
39 #endregion
40
41 #region 跨域的第二种方法
42 //app.Map("/signalr", map =>
43 //{
44 // map.UseCors(CorsOptions.AllowAll);
45 // var hubConfiguration = new HubConfiguration
46 // {
47 // EnableJSONP = true//跨域的关键语句
48 // };
49 // map.RunSignalR(hubConfiguration);
50 //});
51 //app.MapSignalR();
52
53 #endregion
54
55 #region 第二种方法前台代码
56 // <script src="js/jquery-1.8.2.js"></script>
57 // <script src="js/jquery.signalR-2.2.0.min.js"></script>
58 // <script src="http://localhost:23013/signalr/js" type="text/javascript" charset="utf-8"></script>地址是服务器端地址加上/设置的路由/js
59 // <script type="text/javascript">
60 // var chat = $.connection.myHub; //获取服务端实例 首字母小写,不是跟服务端一致的MyHub
61 //console.log(chat);
62 //chat.connection.url = "http://localhost:23013/signalr";测试项目的地址
63 // chat.connection.url = "http://localhost:6874/joey";
64 //1、回调函数 函数名要匹配,参数可以不匹配,后台传过来一个就执行一个,即若后台同时触发了两个同名的sayHello
65 //依次执行
66 //2、一定要有回调函数,不然不算连接成功,可以不调用服务器端的方法。若只是调用服务器端方法,没写回调函数,
67 //依然不算连接成功
68 //3、在连接成功的情况下,后台先执行OnConnected事件,再执行前台调用的某个方法
69 //4、用回调函数来判断是否真的连接成功,$.connection.hub.start().done里直接输出连接成功,是假成功。
70 //5、所以同样,断开连接是否成功也应用回调函数来判断,这个回调函数对应后台代码应在OnDisconnected事件里
71 //6、第五点失败,sayGoodBye是在执行完这个事件(OnDisconnected)后才传输到前台,而事件中执行完已经把链接断开了,前台是接收不到的
72 //chat.client.sayHello = function(connectionCode) {
73 // if(connectionCode == 1)
74 // {
75 // $("#IsConnSuc").val("1");//给隐藏字段赋值,1表示连接成功
76 // alert("连接成功");
77 // }
78 // else
79 // {
80 // alert("连接失败");
81 // }
82 // };
83 //-----------注释掉的---------------------------------------------------------------------
84 // chat.client.sayGoodBye = function(connectionCode) {
85 // if(connectionCode == 1)
86 // {
87 // alert("断开连接成功");
88 // }
89 // else
90 // {
91 // alert("断开连接失败");
92 // }
93 // };
94 // //建立连接
95 // $.connection.hub.start().done(function() {
96 // // Call the Send method on the hub.
97 // chat.server.hello("fd"); //调用服务器端定义的方法 方法名首字母小写,后台对应的方法首字母大小写都能匹配上
98 // });
99 //-----------注释掉的---------------------------------------------------------------------
100 // $(function(){
101 // $("#start").click(function(){
102 // //建立连接
103 // $.connection.hub.start();
104 // });
105
106 // $("#stop").click(function() {
107 // if($("#IsConnSuc").val() == "1"){
108 // //有连接时,才执行断开连接操作
109 // $.connection.hub.stop();
110 // $("#IsConnSuc").val("0");
111 // alert("断开连接成功");
112 // }
113
114 // });
115
116 // });
117
118 //</script>
119 #endregion
http与websocket(基于SignalR)两种协议下的跨域基于ASP.NET MVC--竹子整理的更多相关文章
- 前端跨域问题相关知识详解(原生js和jquery两种方法实现jsonp跨域)
1.同源策略 同源策略(Same origin policy),它是由Netscape提出的一个著名的安全策略.同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正 ...
- 基于 Scrapy-redis 两种形式的分布式爬虫
基于 Scrapy-redis 两种形式的分布式爬虫 .caret, .dropup > .btn > .caret { border-top-color: #000 !important ...
- IIS安全工具UrlScan介绍 ASP.NET 两种超强SQL 注入免费解决方案( 基于IIS,使用免费工具) 批改或隐藏IIS7.5的Server头信息 移除X-Powered-By,MVC,ASP.NET_SessionId 的 HTTP头或者cookie名称
微软给了我们一个很好的工具用来使IIS安全的运行-------UrlScan,下面是它的配置文件介绍 [options]UseAllowVerbs=1 ; 若为1,则使用 ...
- vs中发布WebSever时启用HTTP-POST和HTTP-GET这两种协议
一.问题介绍 在vs中建立一个websever项目时候默认是禁用HTTP-POST和HTTP-GET这两种协议的.但是如果你是在本机上去调试或者是在iis中浏览都会有HTTP-POST这种方式,因为这 ...
- CSharpGL(18)分别处理glDrawArrays()和glDrawElements()两种方式下的拾取(ColorCodedPicking)
CSharpGL(18)分别处理glDrawArrays()和glDrawElements()两种方式下的拾取(ColorCodedPicking) 我在(Modern OpenGL用Shader拾取 ...
- Atitit 如何创新 创新只有在两种条件下发生:自由、效率。
Atitit 如何创新 创新只有在两种条件下发生:自由.效率. 创新是如何发生的呢? 创新只有在两种条件下发生:自由.效率.在自由的环境下,对效率的追逐等于创新.如果你不自由,你的思想不够开阔,你脑洞 ...
- 三种方法实现js跨域访问
转自:http://narutolby.iteye.com/blog/1464436 javascript跨域访问是web开发者经常遇到的问题,什么是跨域,一个域上加载的脚本获取或操作另一个域上的文档 ...
- 基于 HTTP 请求拦截,快速解决跨域和代理 Mock
近几年,随着 Web 开发逐渐成熟,前后端分离的架构设计越来越被众多开发者认可,使得前端和后端可以专注各自的职能,降低沟通成本,提高开发效率. 在前后端分离的开发模式下,前端和后端工程师得以并行工作. ...
- [转] 三种方法实现js跨域访问
1.基于iframe实现跨域 基于iframe实现的跨域要求两个域具有aa.xx.com,bb.xx.com这种特点,也就是两个页面必须属于一个基础域(例如都是xxx.com,或是xxx.com.cn ...
随机推荐
- 分布式Hadoop安装(二)
二.集群环境安装Zookeeper 1. hadoop0,namenode机器下,配置zookeeper,先解压安装包. 使用命令:tar -zxvf zookeeper-3.4.4. ...
- RPC和NFS
参考:http://eduunix.ccut.edu.cn/index2/html/linux/OReilly.SUSE.Linux.Jul.2006/059610183X/suselinux-CHP ...
- android:themes.xml
<?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2006 The Andr ...
- TCP/IP 网络编程 (三)
server端未处理高并发请求通常採用例如以下方式: 多进程:通过创建多个进程提供服务 多路复用:通过捆绑并统一管理 I/O 对象提供服务 多线程:通过生成和客户端等量的线程提供服务 多进程serve ...
- SVN的文件夹链接(目录链接,目录映射,svn:externals)
首先大家可以看下SVN的文件夹链接太强大了!(目录链接,目录映射,svn:externals),我就是看了这篇文章才敢大刀阔斧的把项目里的外链修改成正确的链接. 问题: 我们的项目里,服务器脚本工程s ...
- Asp.net Core WebApi 返回JSON自动驼峰格式化问题
从今天开始,正式进入Asp.net Core的开发,估计最近一段时间会经常写博客了,记录学些Asp.net Core中遇到的各种坑. 第一个问题:通过core编写的webapi,默认返回的json会自 ...
- .net_ckeditor+ckfinder的图片上传配置
CKEditor和CKFinder的最新版可以到官方网站(http://cksource.com)上下载获得. 把以上两个资源放到网站的根目录: /CKEditor 和 /CKFinder (不区分大 ...
- 16.3.1-sp_getapplock
USE TestSystem BEGIN TRANSACTION test1 EXEC [sp_getapplock] 'AppSourceName' , 'Exclusive' WAITFOR DE ...
- linux epoll 开发指南-【ffrpc源码解析】
摘要 关于epoll的问题很早就像写文章讲讲自己的看法,但是由于ffrpc一直没有完工,所以也就拖下来了.Epoll主要在服务器编程中使用,本文主要探讨服务器程序中epoll的使用技巧.Epoll一般 ...
- Eplan 2D安装版布局,部件、端子竖放
部件竖放,不是通过变量的选择实现,而是通过设置实现的,具体设置在: 选项-设置-用户-2D安装板布局: 部件方向-更改为 垂直 部件放置-旋转角度-更改为90° 这样在连续放置部件的时候就变为竖放了, ...