JSONP 解决跨域问题

跨域

协议、域名、端口都相同才算同域,否则就是跨域。

浏览器为了安全考虑(同源策略),不允许 axaj 跨域获取数据。浏览器会报错 xxx has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

但是可以跨域获取文件内容,例如 script 标签、 img 标签可以跨域使用,利用这一点,就可以用 JSONP 进行跨域请求,解决跨域问题。

JSONP

JSONP ( JSON with Padding ) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。

JSONP 由两部分组成:回调函数+数据 。

JSONP 的原理就是动态添加一个 script 标签,而 script 标签的 src 属性是没有跨域的限制的。

后台代码

后台需要用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了。

传统方法:

@RequestMapping("/test")
@ResponseBody
public String test(String callback) {
    Map<String, String> map = new HashMap<String, String>();
    map.put("msg", "hello world!");
    return callback + "(" + JSON.toJSON(map) + ")";
}

spring 4.1 后新特性 :

@RequestMapping("/test")
@ResponseBody
public Object test(String callback) {
    Map<String, String> map = new HashMap<String, String>();
    map.put("msg", "hello world!");
    MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(JSON.toJSON(map));
    mappingJacksonValue.setJsonpFunction(callback);
    return mappingJacksonValue;
}

前端调用

1.利用 script 标签调用
<script type="text/javascript">
    function jsonpCallback(result) {
        console.log(result);
    }
</script>
<script type="text/javascript" src="http://192.168.10.147:8080/zyjyly-1.0/dataApplication/test.do?callback=jsonpCallback"></script>

客户端注册一个 callback ,这里是 jsonpCallback ,然后把 callback 的名字传给服务器,服务端得到这个函数名之后,要用这样的方法 jsonpCallback(...)包裹要输出的 json 内容。 此时服务器生成的json数据才能被客户端正确接收。

运行结果:

{msg: "hello world!"}
2.jQuery 的实现(普通 ajax 方式)

原理是一样的,只不过我们不需要手动的插入 script 标签以及定义回调函数。
jquery 会自动生成一个全局函数来替换 callback=? 中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。

<script type="text/javascript">
    $(function() {
        $.ajax({
            type:'get',
            dataType: 'jsonp',
            url: 'http://192.168.10.147:8080/zyjyly-1.0/dataApplication/test.do',
            success: function (result) {
                console.log(result);
            }
        });
    });
</script>

需要注意下,jsonp 只能用 get 方式去提交。

运行结果:

{msg: "hello world!"}

我们调试下后台代码,可以看到,jquery 会自动生成一个函数,去替换 callback=? 中的问号。

当然,我们也可以自定义 callback 的参数名和回调函数的名称。

<script type="text/javascript">
    $(function() {
        $.ajax({
            type:'get',
            dataType: 'jsonp',
            jsonp: "myCallBack", // 指定 callback 的参数名
            jsonpCallback: "showData",  // 指定回调函数的名称
            url: 'http://192.168.10.147:8080/zyjyly-1.0/dataApplication/test.do',
            success: function (result) {
                console.log("success");
            }
        });
    });
    function showData(result){
        console.log(result);
    }
</script>

这时候,后台方法的参数就要稍微修改下:

@RequestMapping("/test")
@ResponseBody
public Object test(String myCallBack) {
    Map<String, String> map = new HashMap<String, String>();
    map.put("msg", "hello world!");
    MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(JSON.toJSON(map));
    mappingJacksonValue.setJsonpFunction(myCallBack);
    return mappingJacksonValue;
}

运行结果如下:

{msg: "hello world!"}
success
3.jQuery 的实现( $.getJSON 方式)

$.getJSON 方法会自动判断是否跨域,不跨域的话,就调用普通的 ajax 方法;跨域的话,则会以异步加载 js 文件的形式来调用 jsonp 的回调函数。

<script type="text/javascript">
    $(function () {
    $.getJSON("http://192.168.10.147:8080/zyjyly-1.0/dataApplication/test.do?callback=?", function (result) {
        console.log(result);
    });
});
</script>

需要注意下,参数后面必须带上 callback=? 。

JSONP 的弊端:

  • 要对服务器的代码进行改动
  • 只支持 GET 方法(原理是动态创建 script 来进行请求的)
  • 发送的不是 XMLHttpRequest 请求( XMLHttpRequest 请求有很多好用的特性)

总结

一句话就是利用 script 标签绕过同源策略,获得一个类似这样的数据,callback 是页面存在的回调方法,参数就是想得到的 json。

callback({"msg": "hello world!"})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值