一、为什么会出现跨域问题
出于浏览器的同源策略限制。同源策略,所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port),当你需要跨域请求服务的时候就会出现跨域请求问题(浏览器为了上网安全架起同源策略)
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
二、非同源限制(简单地说你跨域请求会失败,并调用不到资源)
【1】无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
【2】无法接触非同源网页的 DOM
【3】无法向非同源地址发送 AJAX 请求
三、解决方法(后端代理或者接口CORS(跨域资源共享))
JSONP跨域(不安全)
JSONP(JSON with Padding)是数据格式 JSON 的一种“使用模式”,可以让网页从别的网域要数据。根据 XmlHttpRequest 对象受到同源策略的影响,而利用 <script>
元素的这个开放策略,网页可以得到从其他来源动态产生的JSON数据,而这种使用模式就是所谓的 JSONP。用JSONP抓到的数据并不是JSON,而是任意的JavaScript,用 JavaScript解释器运行而不是用JSON解析器解析。所有,通过Chrome查看所有JSONP发送的Get请求都是js类型,而非 XHR。
缺点:
只能使用Get请求
不能注册 success、error 等事件监听函数,不能很容易的确定 JSONP 请求是否失败
JSONP 是从其他域中加载代码执行,容易受到跨站请求伪造的攻击,其安全性无法确保
或者使用
window.name+iframe(耗损性能)
iframe一般用来包含别的页面,例如我们可以在我们自己的网站页面加载别人网站的内容,为了更好的效果,可能需要使iframe透明效果,那么就需要了解更多的iframe属性。
window.name通过在iframe(一般动态创建)中加载跨域HTML文件来起作用。然后,HTML文件将传递给请求者的字符串内容赋值给window.name。然后,请求者可以检索window.name值作为响应。
iframe 标签的跨域能力;
window.name 属性值在文档刷新后依旧存在的能力(且最大允许2M左右)。
每个 iframe 都有包裹它的 window,而这个 window 是 top window 的子窗口。contentWindow属性返回元素的Window对象。你可以使用这个Window对象来访问iframe的文档及其内部DOM。
下述用端口:10000表示 — domainA;10001表示 — domainB
<!-- localhost:10000 -->
<script>
var iframe = document.createElement('iframe');
iframe.style.display = 'none'; // 隐藏
var state = 0; // 防止页面无限刷新
iframe.onload = function() {
if(state === 1) {
console.log(JSON.parse(iframe.contentWindow.name));
// 清除创建的iframe
iframe.contentWindow.document.write('');
iframe.contentWindow.close();
document.body.removeChild(iframe);
} else if(state === 0) {
state = 1;
// 加载完成,指向当前域,防止错误(proxy.html为空白页面)
// Blocked a frame with origin "http://localhost:10000" from accessing a cross-origin frame.
iframe.contentWindow.location = 'http://localhost:10000/proxy.html';
}
};
iframe.src = 'http://localhost:10001';
document.body.appendChild(iframe);
</script>
<!-- localhost:10001 -->
<!DOCTYPE html>
...
<script>
window.name = JSON.stringify({a: 1, b: 2});
</script>
</html>
注意:
直接嵌入其他域(localhots:10001)下的URL会报错,所以需要加载完成替换为当前域的URL(localhots:10000),proxy.html为空白页面,只为解决该问题;
在这里插入图片描述
重新设置 src(http://localhost:10000/proxy.html)后导致页面不断刷新,所以通过 state 来控制;
全部获取完结果后,清除该 iframe。