什么是跨域
在讲jsonp跨域访问之前有必要先讲一下什么是跨域,所谓的跨域就是跨域名,跨端口,跨协议,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。如下:
http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)
http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)
http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)
http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
JSONP原理
- 客户端利用script标签可以跨域请求资源的性质,向网页中动态插入script标签,来向服务端请求数据。
- 服务端会解析请求的url,至少拿到一个回调函数(比如callback=myCallback)参数,之后将数据放入其中返回给客户端。
- 当然jsonp不同于平常的ajax请求,它仅仅支持get类型的方式
JSONP具体实现
- 普通方法
<!DOCTYPE html> <html> <head> <title>JSONP跨域</title> </head> <body> <script type="text/javascript"> function jsonMethod(data){ alert("age:" + data.age + "name:" + data.name); } </script> <script type="text/javascript" src="jquery-1.8.3.min.js"> </script> <script type="text/javascript" src="http://www.practice-zhao.com/remote.js"></script> </body> </html>
上面代码在域www.practice.com下,script标签的src指向了不同域的脚本代码。remote.js代码如下:
jsonMethod({ "age" : 15, "name": "John", })
也就是这段远程的js代码执行了上面定义的函数,弹出了提示框
下面将前端代码进行修改
<script type="text/javascript"> function jsonMethod(data){ alert("age:" + data.age + "name:" + data.name); } </script> <script type="text/javascript" src="jquery-1.8.3.min.js"> </script> <script type="text/javascript"> $(document).ready(function(){ var url = "http://www.practice-zhao.com/student.php?id=1&callback=jsonMethod"; var obj = $('<script><\/script>'); obj.attr("src",url); $("#div1").append(obj); }); </script>上面代码添加了一个script标签,src指向跨域的一个php脚本,并且将上面的js函数名作为callback参数传入,那么我们看下后端代码怎么写的:
<?php $data = array( 'age' => 20, 'name' => '张三', ); $callback = $_GET['callback']; echo $callback."(".json_encode($data).")"; return;PHP代码返回了一段JS语句,即
jsonMethod({ "age" : 15, "name": "张三", })此时访问页面时,动态添加了一个script标签,src指向PHP脚本,执行返回的JS代码,成功弹出提示框。
所以JSONP将访问跨域请求变成了执行远程JS代码,服务端不再返回JSON格式的数据,而是返回了一段将JSON数据作为传入参数的函数执行代码。
jquery方法
<script> $(document).ready(function () { $("#btn").click(function () { $.ajax({ url: "http://localhost:9090/student", type: "GET", dataType: "jsonp", //指定服务器返回的数据类型 success: function (data) { var result = JSON.stringify(data); //json对象转成字符串 $("#text").val(result); } }); }); }); </script>
调用结果如下,注意看下图划线的url
再看看如何指定特定的回调函数回调函数你可以写到<script>下(默认属于window对象),或者指明写到window对象里,看jquery源码,可以看到jsonp调用回调函数时,是调用的window.callback。
然后看调用结果,发现,请求时带的参数是:callback=showData;调用回调函数的时候,先调用了指定的showData,然后再调用了success。所以,success是返回成功后必定会调用的函数,就看你怎么写了。
<script> 7 8 function showData (data) { 9 console.info("调用showData"); 10 11 var result = JSON.stringify(data); 12 $("#text").val(result); 13 } 14 15 $(document).ready(function () { 16 17 // window.showData = function (data) { 18 // console.info("调用showData"); 19 // 20 // var result = JSON.stringify(data); 21 // $("#text").val(result); 22 // } 23 24 $("#btn").click(function () { 25 26 $.ajax({ 27 url: "http://localhost:9090/student", 28 type: "GET", 29 dataType: "jsonp", //指定服务器返回的数据类型 30 jsonpCallback: "showData", //指定回调函数名称 31 success: function (data) { 32 console.info("调用success"); 33 } 34 }); 35 }); 36 37 }); 38 </script>
另外zepto.js也有提供jsonp实现的api,具体可自行去zepto官网查看。