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)前端代码:
代码语言:javascript复制<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数据
接口返回的数据格式如下:
代码语言:javascript复制{"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函数,例如:
代码语言:javascript复制<%@ 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方式的。