前端跨域解读

前端跨域
前言
在多业务多平台的场景下,不可避免的会遇到业务整合或者页面整合的过程,而跨域通讯是必备的技能点,其中一个非常常见的点就是iframe自动根据载入页面高度撑大。其他方面需要跨域传值,保存页面基本信息等都离不开这项基本技术。
跨域概念
跨域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就被当作是跨域。可以通过以下例子更好的理解跨域概念。
(限制跨域是浏览器的问题,不是js的问题)
url
说明
是否允许通讯
http://www.a.com/a.js;
http://www.a.com/b.js
同一域名不同文件
允许
http://www.a.com/js/a.js;
http://www.a.com/script/b.js
同一域名不同目录
允许
http://www.a.com:8000/js/a.js; http://www.a.com/script/b.js
同一域名,不同端口
不允许
http://www.a.com/a.js;https://www.a.com/b.js
同一域名,不同协议
不允许
http://www.a.com/a.js;http://70.32.92.74/b.js
域名和域名对应ip
不允许
http://www.a.com/a.js;http://script.a.com/b.js
主域相同,子域不同
不允许
http://www.a.com/a.js;http://a.com/b.js
同一域名,不同二级域名(同上)
不允许
http://www.cnblogs.com/a.js;http://www.a.com/b.js
不同域名
不允许
备注:以下方案均以a.htm嵌入b.htm为例
方案汇总
方案一:document.domain
前提:主域相同,没有兼容问题
原理:设置为同一域名,改变识别标识
具体方案:
1 . 在www.a.com/a.html 中 :document.domain = ‘a.com’;
2 . 在www.script.a.com/b.html 中:document.domain = ‘a.com’;
方案二:动态创建script(可以忽略)
前提:无
原理:因为script标签不受同源策略的限制
具体方案:可以动态创建,也可以直接引入其他域名下的js文件,其中的js方法也可以直接使用。

附:js原生手写写法
function loadScript(url, func) {
var head = document.head || document.getElementByTagName(‘head’)[0];
var script = document.createElement(‘script’);
script.src = url;
script.onload = script.onreadystatechange = function(){
if(!this.readyState || this.readyState==‘loaded’ || this.readyState==‘complete’){
 func();
 script.onload = script.onreadystatechange = null;}
};
 head.insertBefore(script, 0);
}
window.baidu = { sug: function(data){console.log(data); }}
loadScript(‘http://suggestion.baidu.com/su?wd=w’,function(){console.log(‘loaded’)});
方案三 :window.name
window.name 可以实现跨域存储,需要借助中介界面(/proxy.html);存储大小2M.
具体方案:
a.com/a.html

b.com/b.html :
var jsonData={
“name":value,
“name2”:value2
}
window.name=JSON.stringify(jsonData);// 建议用json格式,也可以为字符串
方案四:jsonp ,推荐方式(只能get的方式??兼容性比较好???)
最为推荐的跨域解决方案,没有兼容问题
具体方案:
前提:需要b.com准备一个响应的json文件或者数据,比如
inf({
“code”:“ZJ2017”,
"price":1788,
“tickets”:100
});
原生js方式
var script=document.createElement(“script”);
script.src=“http://www.b.com/demo.json?callback=inf”;
document.body.appendChild(script);
function inf(json){
console.log(json);
}
ajax :jsonp方式
KaTeX parse error: Expected '}', got '#' at position 1123: …h){  case '#̲data':  … /$1 break;
 include uwsgi_params;
 proxy_pass http://localhost:1894;
}
开发阶段,vue提供了其转发的方式,参考如下设置。
proxyTable: {
‘/api/’: {
target: ‘http://172.16.75.117:3003/’,
changeOrigin: true,
pathRewrite: {
‘^/api/’: '/'
}
}
方案十 :alloy团队 messengerJs
依赖原理 :对于现代浏览器,postMessage API还是无可撼动的。IE6/7下,使用的是一个被认为是bug或安全漏洞的特性,即navigator对象在父窗口和iframe之间是共享的。基于这一点,我们可以在父窗口中,在navigator对象上注册一个消息回调函数;在iframe中,调用navigator上的这个函数并传入参数。此时可看作,iframe往父窗口的一个函数传递了一个参数,并在父窗口的上下文中执行了,那么就相当于iframe向父窗口发送了一条消息。反之亦然。
git地址 :http://biqing.github.io/MessengerJS/
文档介绍: http://www.alloyteam.com/2013/11/the-second-version-universal-solution-iframe-cross-domain-communication/
备注 :没有亲自实践过,可用性待定???
更多
关于option预检请求(preflight)
一般情况下这个预检请求是发生在跨域的大前提下,浏览器对跨域下的请求分为两大类:分别为简单请求和非简单请求。那么不符合以下两个条件的就都是复杂请求,对于复杂请求,浏览器会发送一次option预检请求,如果服务器允许,那么再发送正常的请求。
那么,简单请求的要求是 :
一 请求方法是以下三种方法之一:
HEAD
GET
POST
二 HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
cors方案
备注:首先,options请求首先是浏览器再复杂请求并且跨域的前提下产生的,在实际的部署环境,比如nginx下是通过转发请求的,没有这个问题。如果一定要去掉或者优化预检请求,可以通过:
1 把不必要的请求换为简单请求 (可行性不大)
2 后端设置options请求的有效时长变长,现状:默认的chrome的预检请求保持5s,设置header的access-control-max-age来增长缓存时间(只有第一次会请求)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JackieChan_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值