JSONP原理以及示例(jsonp示例)
JSONP原理
首先我们需要明白,在页面上直接发起一个跨域的ajax请求是不可以的,但是,在页面上引入不同域上的js脚本却是可以的,就像你可以在自己的页面上使用<img src=""> 标签来随意显示某个域上的图片一样。比如我在8080端口的页面上请求一个9090端口的图片:
可以得出结论:对于<img><script>这类标签中的src属性是可以跨域请求的(可以看作是浏览器给我们留下一个跨域访问的后门)。
1)原理:
JSONP就是利用了<script>标签的src属性发起的跨域请求,由于script标签的作用是用来执行src指定的js代码。那么我们可以跟后端协商一个函数名,后端将要返回的数据作为函数的参数,一起返回给前端,前端事先定义好该函数,这样就完成了跨域请求。
2)JSONP的缺点:
- 首先,它没有关于JSONP调用的错误处理,一旦回调函数调用失败,浏览器会以静默失败的方式处理。
- 其次,它只支持GET请求,这是由于该技术本身的特性所决定的。因此,对于一些需要对安全性有要求的跨域请求,JSONP的使用需要谨慎一点了。
- JSONP不支持用async:false的方法设置同步。
3)JSONP的优点:
由于JSONP对于老浏览器兼容性方面比较良好,因此,对于那些对IE8以下仍然需要支持的网站来说,仍然被广泛应用。不过,针对高级浏览器,建议还是用CORS 方法。
示例:
jquery的jsonp跨域示例:
1、配置dataType:
服务端代码同上,ajax请求时只需配置一个dataType:'jsonp',就可以发起一个跨域请求。
(1)前端代码:
<html> <head> <title>跨域测试</title> <script src="js/jquery-1.7.2.js"></script> <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> </head> <body> <input id="btn" type="button" value="跨域获取数据" /> <textarea id="text" style="width: 400px; height: 100px;"></textarea> </body> </html>
(2)服务端返回json数据
接口返回的数据格式如下:
{"code":1,"msg":"成功","time":"1708328162","data":[{"id":1,"title":"客服微信","number":"everfor888"},{"id":2,"title":"客服邮箱","number":"xianji568@163.com"}]}
(3)说明:
jsonp指定服务器返回的数据类型为jsonp格式。从请求的url上可以看到,自动带了一个callback=xxx,xxx是jquery随机生成的一个回调函数。
jquery配置jsonp后会随机生成回调函数,当返回jsonp的数据后,执行该回调函数,只不过默认jquery会将这个执行动作映射到success中。
2、指定回调函数:
可以通过jsonpCallback属性指定函数的名称,然后显示的将指定的jsonp回到函数写到<script>下(默认属于window对象),或window对象里。
我们都知道,ajax执行成功后会调用success函数,那上面那种指定了jsonp后,会不会调用success呢?答案是会,而且是先执行jsonp的回调函数,再执行ajax的success函数,例如:
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>跨域测试</title> <script src="js/jquery-1.7.2.js"></script> <script> function showData (data) { console.info("调用showData"); var result = JSON.stringify(data); $("#text").val(result); } $(document).ready(function () { // window.showData = function (data) { // console.info("调用showData"); // var result = JSON.stringify(data); // $("#text").val(result); // } $("#btn").click(function () { $.ajax({ url: "http://localhost:9090/student", type: "GET", dataType: "jsonp", //指定服务器返回的数据类型 jsonpCallback: "showData", //指定回调函数名称 success: function (data) { console.info("调用success"); } }); }); }); </script> </head> <body> <input id="btn" type="button" value="跨域获取数据" /> <textarea id="text" style="width: 400px; height: 100px;"></textarea> </body> </html>
3、指定回调函数的参数名:
我们可以通过jsonp属性,来指定回调函数的参数名称,默认是callback。
jsonpCallback: "showData", //指定回调函数名称
4、看看jquery的jsonp是否支持POST方式:
jsonp方式不支持POST方式跨域请求,就算这里指定成POST方式,也会自动转为GET方式;而后端如果设置成POST方式了,那就请求不了了。
jsonp的实现方式其实就是<script>脚本请求地址的方式一样,只是ajax的jsonp对其做了封装,所以可想而知,jsonp是不支持POST方式的。