由于 XMLHTTPRequest 对象不支持跨域的异步请求,所以当需要请求跨域的数据时,使用 XMLHTTPRequest 是无法实现的。
之前博客中曾说道 script 、 link 、 img 、 iframe 标签支持跨域请求。但是 img 返回的是图片格式,无法返回数据; link 只有在 rel="stylesheet" 时支持跨域,且在css渲染阶段会报错; iframe 使用起来过于复杂,且现在的web规范是尽可能避免使用 iframe ,所以 script 就成了首选的跨域解决方案。
使用 script 标签解决跨域问题的思路是:
- 挂载一个全局函数用于处理数据。
- 处理webAPI的url,具体做法是在url后面添加一个新的跨域请求参数,以豆瓣的电影热映API为例:
http://api.douban.com/v2/movie/in_theaters?callback=jsonp这里的callback就是一个跨域请求的参数,jsonp为全局函数的变量名。 - 创建一个
script节点并将其src赋值为前面请求的url。 - 添加
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请求头
响应体
至此,跨域的解决方案告终。
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。