jQuery的ajax跨域 Jsonp原理
1、Jsonp
Jsonp(json with padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。
Jsonp是为了解决ajax跨域发送http请求出现的,利用Script标签的特性跨域。浏览器由于安全考虑,在编写ajax程序时,httprequest/xmlhttp都不能发送非本域的http请求,是被浏览器所禁止的。所以ajax本身是无法跨域的。
2、同源策略
www.a.com网页的ajax获取www.b.com接口的内容,由于您的网页域名是www.a.com,而您发送的ajax请求的目标域却是www.b.com。浏览器会阻止这一的请求,这就是所谓的同源策略。
同源是指:js脚本只能访问或者请求相同协议,相同domain(网址/ip),相同端口的页面。
我们知道,js脚本可以访问所在页面的所有元素。通过ajax技术,js也可以访问同一协议,同一个domain(ip),同一端口的服务器上的其他页面,请求到浏览器端之后,利用js就可以进行任意的访问。但是对于协议不同, 或者domain不同或者端口不同的服务器上的页面就无能为力了,完全不能进行请求。下面是例子:(http://localhost:57269/页面)
<script type="text/javascript"> var xmlhttp; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } else { xmlhttp = ActionXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { console.log(xmlhttp.responseText); } } var url = "http://localhost:51355/Common/Test"; xmlhttp.open("Get", url, true); xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xmlhttp.send(); </script>
这里为了结果不受其他js库的干扰,使用了原生的XMLHttpRequest来处理,结果如下:
我们看到57269端口的ajax请求无法访问51355端口的页面。原因是“同源策略禁止读取“某某”的远程资源”。因为同源策略,普通的ajax无法跨域请求,解决这种问题的方式就是Jsonp。
3、Jsonp跨域的原理
我们发现凡是拥有"src"这个属性的标签都拥有跨域的能力,在页面上有三种资源是可以与页面本身不同源的。它们是:js脚本,css样式文件,图片,如下所示,它们是可以链接访问到不同源的资源的。
1)<script type="text/javascript" src="某个cdn地址" ></script>
2)<link type="text/css" rel="stylesheet" href="某个cdn地址" />
3)<img src="某个cdn地址" alt=""/>
而jsonp就是利用了<script>标签可以链接到不同源的js脚本,来达到跨域目的。当链接的资源到达浏览器时,浏览器会根据他们的类型来采取不同的处理方式,比如,如果是css文件,则会进行对页面 repaint,如果是img 则会将图片渲染出来,如果是script 脚本,则会进行执行,比如我们在页面引入了jquery库,为什么就可以使用 $ 了呢?就是因为jquery库被浏览器执行之后,会给全局对象window增加一个属性:$,所以我们才能使用 $ 来进行各种处理。(另外为什么要一般要加css放在头部,而js脚本放在body尾部呢,就是为了减少repaint的次数,另外因为js引擎是单线程执行,如果将js脚本放在头部,那么在js引擎在执行js代码时,会造成页面暂停。)
jQuery封装的 josnp 用法:
<script type="text/javascript"> //第一种方式getJSON callback=?,其中 ? 会自动替换为function(data)函数。 $.getJSON("http://localhost:51355/Common/Test?callback=?", function(data) { var obj = JSON.parse(data); //很多网上的例子都是可以直接.age这样写的,但是我测试的时候无法这么做,必须要转一次josn,需要转josn,未能清楚为何没有自动为我转成json格式。 alert(obj.age); }); //第二种方式ajax,设定请求方式为jsonp $.ajax({ async: false, url: "http://localhost:51355/Common/Test", //跨域的url type: "GET", dataType: 'jsonp', //返回格式 jsonp: "callback", //指定回调函数 data: "", //参数 success: function(data) { var obj = JSON.parse(data); //很多网上的例子都是可以直接.age这样写的,但是我测试的时候无法这么做,必须要转一次josn,需要转josn,未能清楚为何没有自动为我转成json格式。 alert(obj.age); } }); //需要考证是否正确 //jsonp: "callback", // 指定回调函数,这里名字可以为其他任意你喜欢的,比如callback,不过必须与下一行的GET参数一致 //data: "name=jxq&email=feichexia@yahoo.com.cn&callback=?", // callback与上面的jsonp值一致 </script>
C# MVC代码:
//方式一 public ActionResult Test() { string callback = Request["callback"]; //jsonp1503629838983 string name = "cang"; string age = "20"; string response = "{\"name\":\"" + name + "\",\"age\":\"" + age + "\"}"; System.Web.Script.Serialization.JavaScriptSerializer jss = new System.Web.Script.Serialization.JavaScriptSerializer(); string call = callback + "(" + jss.Serialize(response) + ")"; //jsonp1503629838983("{\"name\":\"cang\",\"age\":\"20\"}") return Content(call); } //方式二 public void Test() { string callback = Request["callback"]; //jsonp1503629838983 string name = "cang"; string age = "20"; string response = "{\"name\":\"" + name + "\",\"age\":\"" + age + "\"}"; System.Web.Script.Serialization.JavaScriptSerializer jss = new System.Web.Script.Serialization.JavaScriptSerializer(); string call = callback + "(" + jss.Serialize(response) + ")"; //jsonp1503629838983("{\"name\":\"cang\",\"age\":\"20\"}") Response.Write(call); Response.End(); }
下面是我理解的josnp的原理(个人观点):
一个简单的JSONP请求可以通过一下代码实现:
<script type="text/javascript"> var callbackName = 'callback'; window[callbackName] = function(data) { var obj = JSON.parse(data); //很多网上的例子都是可以直接.age这样写的,但是我测试的时候无法这么做,必须要转一次josn,需要转josn,未能清楚为何没有自动为我转成json格式。 alert(obj.age); } var script = document.createElement('script'); script.src = 'http://localhost:51355/Common/Test?callback=' + callbackName; document.body.appendChild(script); </script>
大概可以看出来,是创建了一个<script>标签,然后把我想请求的地址赋值给src。这样我是不是可以继续精简一下。
Html的head代码:
<head> <script> function callback(data) { var obj = JSON.parse(data); //转josn alert(obj.age); } </script> <script src="http://localhost:51355/Common/Test?callback=callback" type="text/javascript"></script> </head>
4、总结
1、这是我认为的josnp代码实现方式,应该是先创建了一个类似callback函数,然后创建一个<script>的标签,通过标签中的src指定的js脚本到达浏览器会执行的特性,发起请求告诉服务端函数名叫callback。html会把返回的字符串当作javascript代码来进行解析,然后返回的是一个函数包裹的josn数据callback(josn),即callback("{\"name\":\"cang\",\"age\":\"20\"}"),然后调动本地的callback函数输出josn。
2、jQuery是将jsonp封装成类似ajax的样子,是自动生成回调函数并把数据取出来供success属性方法来调用。
3、因为<script>标签的请求方式就是Get。所以Jsonp只能使用Get请求,即使jQuery方式的ajax里写的是post方式,最后也是get方式请求。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?