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方式的。

 

备注:有时候会遇到不支持jsonp的情况,这种可能是后端做了某些限制,只能放弃该方案了

THE END