由于 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请求头

响应体
至此,跨域的解决方案告终。
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。