天天看点

JSONP实现跨域原理

      浏览器只对XMLHttpRequest请求有同源请求限制,而对script标签src属性、link标签ref属性和img标签src属性没有这这种限制,利用这个“漏洞”就可以很好的解决跨域请求。JSONP就是利用了script标签无同源限制的特点来实现的。当然需要后端服务器的配合,返回一个合法的JS脚本,一般是一条调用js函数的语句,数据作为函数的入参。

       看下面的例子:

       接口:    

@RestController
public class ApiTestController {
    @GetMapping("/api/test")
    public void index(String callback ,HttpServletResponse response) throws Exception {
        //response.setHeader("Access-Control-Allow-Origin","*");
        HashMap<String, Object> map = new HashMap<>();
        map.put("hello","test");
        map.put("name","test");
        map.put("age",11);
        map.put("sex","f");
        Object o = JSON.toJSON(map);
        response.getWriter().write(callback+"("+ o +")");
    }

}
           

这个Controller很简单,负责将数据包装成callback({})的形式,返回客户端,最终的数据是callback({hello:'test',name:'test',age:11,sex:'f'}),从js的语法来看,这不就是一个简单的函数调用吗?其中函数的参数已经设置好了,就是接口要返回的数据,对于callback是由前端请求的一个参数,代表前端js使用的回调函数。

前端代码:

<script>
	function jsonp(data) {
	   console.log(data)
	}
</script>   
<script src="http://localhost/api/test?callback=jsonp"></script>
           

在前面说了,浏览器对script 标签发送的请求没有跨域限制,所以使用script标签对接口发起请求,服务器端接收请求之后返回这样的数据jsonp({hello:'test',name:'test',age:11,sex:'f'}) ,由于是script标签发送的请求,所以浏览器会将响应当作js脚本执行,也就是调用jsonp函数,这样数据就拿到了。需要注意的是,接口返回的字符串必须是合法的js语句,否则浏览器执行js时会报错。

JSONP 使用简单且兼容性不错,但是只限于 

get

 请求。在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的,这时候就需要自己封装一个 JSONP,以下是简单实现:

function jsonp(url, jsonpCallback, success) {
  let script = document.createElement("script");
  script.src = url;
  script.async = true;
  script.type = "text/javascript";
  window[jsonpCallback] = function(data) {
    success && success(data);
  };
  document.body.appendChild(script);
}
jsonp(
  "http://xxx",
  "callback",
  function(value) {
    console.log(value);
  }
);