[聚合文章] 手写跨域解决方案

JSONP 2017-01-28 15 阅读

由于 XMLHTTPRequest 对象不支持跨域的异步请求,所以当需要请求跨域的数据时,使用 XMLHTTPRequest 是无法实现的。

之前博客中曾说道 scriptlinkimgiframe 标签支持跨域请求。但是 img 返回的是图片格式,无法返回数据; link 只有在 rel="stylesheet" 时支持跨域,且在css渲染阶段会报错; iframe 使用起来过于复杂,且现在的web规范是尽可能避免使用 iframe ,所以 script 就成了首选的跨域解决方案。

使用 script 标签解决跨域问题的思路是:

  1. 挂载一个全局函数用于处理数据。
  2. 处理webAPI的url,具体做法是在url后面添加一个新的跨域请求参数,以豆瓣的电影热映API为例: http://api.douban.com/v2/movie/in_theaters?callback=jsonp 这里的 callback 就是一个跨域请求的参数, jsonp 为全局函数的变量名。
  3. 创建一个 script 节点并将其 src 赋值为前面请求的url。
  4. 添加 script 到dom树中。

回想一下jQuery中jsonp的使用方法:

$.ajax({
        url:"http://api.douban.com/v2/movie/in_theaters",
        data:{count:10,start:10},
        dataType:'jsonp',
        jsonp:/*此处就是跨域的请求参数名称,jQuery默认是callback*/,
        jsonpCallback:/*全局函数的变量名,jQuery中默认会随机生成一个变量名*/
        success:function(data){
            console.log(data);
        },
        error:function(err){
            console.log(err);
        }
        });

模拟jQuery的跨域写法,可以写一个自己的跨域方案,因为如果单纯的为了使用jQuery的跨域方法而去引入一个100多K的包显然是不划算的。

jsonp.js

// jsonp.js
let jsonp = (data,cb)=> {
  // 处理请求参数
  const {url,qs} = data;
  // 定义callback名称
  const cb_name = `cb_${Math.random().toString().replace('.','')}`;
  // // 挂载callback
  window[cb_name] = cb;
  // // 处理url
  let symbol = (url.indexOf('?')===-1) ? '?' : '&';
  let params_from_qs = '';
  for(let key in qs) {
    params_from_qs += `${key}=${qs[key]}&`;
  }
  let complete_url = `${url}${symbol}${params_from_qs}callback=${cb_name}`;
  // 挂载script
  let script = document.createElement('script');
  script.src = complete_url;
  document.body.appendChild(script);
}

test.html

<body>
<script src="jsonp.js"></script>
<script>

    jsonp({
        url:'http://api.douban.com/v2/movie/in_theaters',
        data:{count:5,start:2},
    },(res)=>{console.log(res);});
</script>
</body>
</html>

可以看到

jsonp请求头

响应体

至此,跨域的解决方案告终。

注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。