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 : Hub5 {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:PersistentConnection2 {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 }
View Code
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 HubConfiguration5 {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类中还有个组属性,尚待开发,待看文档,再写demo4 /// </summary>5 public class MyHub : Hub6 {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 }
View Code
3、我们的客户端
第一步:获取实例,建立连接
var chat = $.connection.myHub; //获取服务端实例 首字母小写,不是跟服务端一致的MyHubchat.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) {//处理dataalert(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
View Code
我比较喜欢下面这种简洁的方式:
$.ajax({type:"GET",url:"http://localhost:6874/Admin/Login/IsLegal", //跨域URLdataType:"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 #endregion4 5 #region 跨域的第一种方法6 //这个参数"/echo",是我们自己定义的一个路由,与客户端创建SignalR的实例时对应。7 app.Map("/echo",8 map =>9 {10 map.UseCors(CorsOptions.AllowAll);11 map.RunSignalR<EchoConnection>();12 }13 );14 #endregion15 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 #endregion40 41 #region 跨域的第二种方法42 //app.Map("/signalr", map =>43 //{44 // map.UseCors(CorsOptions.AllowAll);45 // var hubConfiguration = new HubConfiguration46 // {47 // EnableJSONP = true//跨域的关键语句48 // };49 // map.RunSignalR(hubConfiguration);50 //});51 //app.MapSignalR();52 53 #endregion54 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>地址是服务器端地址加上/设置的路由/js59 // <script type="text/javascript">60 // var chat = $.connection.myHub; //获取服务端实例 首字母小写,不是跟服务端一致的MyHub61 //console.log(chat);62 //chat.connection.url = "http://localhost:23013/signalr";测试项目的地址63 // chat.connection.url = "http://localhost:6874/joey";64 //1、回调函数 函数名要匹配,参数可以不匹配,后台传过来一个就执行一个,即若后台同时触发了两个同名的sayHello65 //依次执行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 // else79 // {80 // alert("连接失败");81 // }82 // };83 //-----------注释掉的---------------------------------------------------------------------84 // chat.client.sayGoodBye = function(connectionCode) {85 // if(connectionCode == 1)86 // {87 // alert("断开连接成功");88 // }89 // else90 // {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
View Code
转载于:https://www.cnblogs.com/joeymary/p/5259464.html
http与websocket(基于SignalR)两种协议下的跨域基于ASP.NET MVC--竹子整理相关推荐
- 继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错? springboot 两种方式稳定解决跨域问题
继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错???springboot 两种方式稳定解决跨域问题! 之前我写了一篇文章,来解决CORS报错 ...
- (4)高通AP10.4开发者指南——WLAN(1.4 Offload和direct-attach两种模式下驱动的模块化)
1.4 Offload和direct-attach两种模式下驱动的模块化 这一章节主要描述当前WLAN驱动,模块化的设计与实现.Offload后续缩写为OL,Direct-Attach缩写为DA. W ...
- 电动汽车 V2G 放电模型 算法 考虑电动汽车家庭慢充和充电站快充两种模式下,模拟出一定数量电动汽车的日负荷曲线
电动汽车 V2G 放电模型 算法 包含两个程序,均基于matlab,实现以下两个功能: 1.考虑电动汽车家庭慢充和充电站快充两种模式下,模拟出一定数量电动汽车的日负荷曲线: 2.考虑V2G的电动汽车放 ...
- 进一步封装axios并调用其读取数据(吐槽~在安卓9.0以下或者IOS10.X以下手机端H5页面不支持,在这两种情况下的系统只能使用ajax或者原生js请求后台数据)
注意!!!(修改于2020年7月18日) 在安卓9.0以下或者IOS10.X以下手机端H5页面不支持,在这两种情况下的系统只能使用ajax或者原生js请求后台数据 报错截图如下 报错内容: {&quo ...
- hover在两种情况下的两种用法
:hover在鼠标移到链接上时添加的特殊样式. 提示: :hover 选择器器可用于所有元素,不仅是链接. 提示: :link 选择器设置了未访问过的页面链接样式, :visited 选择器设置访问过 ...
- 如何在word2016 和2021(ps:这两种环境下我都装了)安装Mathtype7.4 彻底解决安装Mathtype7.4之后粘贴显示:运行时错误‘53’,文件未找到:MathPage.WL
需要安装文件放在了资源区 如何在word2016和2021(ps:这两种环境下我都装了)安装Mathtype7.4彻底解决安装Mathtype7.4之-数据集文档类资源-CSDN下载 2.文件 Mat ...
- 频率控制和滞环控制的半桥/全桥LLC电路仿真对比 两种方式下均可实现输出电压闭环控制 ,模型中包含负载的阶跃变化过程 ,可以验证闭环系统稳定性
频率控制和滞环控制的半桥/全桥LLC电路仿真对比 两种方式下均可实现输出电压闭环控制 ,模型中包含负载的阶跃变化过程 ,可以验证闭环系统稳定性 滞环控制和变频控制下的电感电流和输出电压波形图如第二幅图 ...
- 虚拟主机3种方式nginx/apache+跨域知识点整理
目录 referer.prototype.array.json笔记整理: [http://t.csdn.cn/s4P8x](http://t.csdn.cn/s4P8x) 虚拟主机3种方式nginx/ ...
- 9种常见的前端跨域解决方案
9种常见的前端跨域解决方案(详解) 2019.09.02 21:54 73879浏览 一.什么是跨域? 在前端领域中,跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能同源使用的限制. ...
最新文章
- 控件不支持html5,javascript – HTML5视频控件不起作用
- Linux 之十二 Makefile 从入门到放弃全解
- block学习(一)
- Centos安装Vmware-Tools工具
- 一个简单的MVC模式练习
- js字符串replace替换多个_汇总几大python常见字符串处理函数与用法(建议收藏)...
- 关于phi函数的积性性质的一个证明
- 《Photoshop Lightroom4 经典教程》—第1课复习题答案
- 一个超好用的笔记编辑器
- 易语言 html邮件,易语言邮件收发源码
- 微信小程序 --- 物流快递查询
- 如何用原生js获取非行间样式
- Flowchart流程图示例
- [光劍藏書館2020] 孔夫子旧书网
- 【Vmware】打开虚拟机时提示“无法连接虚拟设备,因为主机上没有响应的设备”
- 百度地图让用户“私人定制“:一场语音定制背后的AI能力强势输出
- JUC-BlockingQueue二
- 思科、华为、华三模拟器大比拼,你最爱哪一款?(附模拟器下载)
- c程序语言中long,C语言long
- Canvas模拟太阳地球月球的运动过程
热门文章
- bat脚本交互输入_windows 10 如何设定计划任务自动执行 python 脚本?
- 修补工具为什么修不干净_超声波洗不干净牙齿吗?为什么还要喷砂?
- php连接mysql原生_php链接mysql原生写法
- promise async await
- pytorch torch.nn.RNN
- 02 unix文件系统和命令
- MySQL Date and Time Types(日期和时间格式)
- Pandas Index 属性
- Pandas 文本数据方法 is*()
- python 菜品识别_利用百度智能云结合Python体验图像识别(来自qylruirui)