javascript基础--跨域
来源:互联网 发布:使命召唤12cpu优化 编辑:程序博客网 时间:2024/05/29 19:28
引言
为什么会有跨域,什么是跨域,这些疑问在没有接触它之前都是正常的。简单的来讲,是因为某些人利用加载外部域的外部脚本代码来搜集原网站信息,以致各种信息泄露,财产损失等现象发生。所以javascript出于安全的角度,提出同源策略,禁止加载不同域下的资源。但是我们开发人员有时的确也有需要使用外部资源,怎么办呢?这就是跨域。
1.什么是跨域
域名的组成:
判定方法:
- 1.当协议,子域名,主域名,端口号四个之间任意一个不同时,都算不同域
- 2.不同域名之间请求资源就算跨域
示例:
//请求不同的资源http://www.baidu.com/index.html http://www.baidu.com/1.png 非跨域//协议不同http://www.baidu.com/index.html https://www.baidu.com/index.html 跨域 //子域名不同http://www.baidu.com/index.html http://bbs.baidu.com/index.html 跨域 //主域名不同http://www.baidu.com/index.html http://www.sina.com/index.html 跨域 //端口号不通http://www.baidu.com:80/index.html http://www.baidu.com:81/index.htm 跨域
2.跨域方法一: document.domain
首选得知道document.domain是什么?
释义:document.domain返回当前文档的域名,可以试试,我用的bing搜索,没有广告哦。
可以打印那么可以赋值修改domain吗?试试就知道了
可见document.domain修改是有原则的,具体有两条
- 可以修改为本身,相当于没做修改(感觉被耍了)
- 可以修改为本身的主域名(跨域就从这里做文章)
这么讲,假设你们班上没有同名的人。你叫李小明,别人可以叫你李小明,也可以叫你小明,不可能叫你李大明,周小明。老师提问,叫到李小明,你肯定一下子就站起来了。如果恰好你们班上有个人叫王小明,那老师叫小明,谁又该站起来呢。所以跨域也是这个道理,利用这种歧义,让“名字”相同,“姓氏”不同的人,实现共享信息
举个例子:www.baidu.com下面www是子域名,baidu.com是主域名。所以要修改,只有两种可能,其它情况都不行
- 第一,修改为www.baidu.com
- 第二,修改为baidu.com
我们实现跨域主要是依靠第二个结果来做文章。所以document.domain只对主域名相同,子域名不同的情况实现跨域。为什么这样讲?看看例子。
准备好两个页面:www.a.com cn.a.com —> 两个域名的主域名都是a.com,子域名不同
实现方式:借助Frame对象
www.a.com a.html页面
document.domain = 'a.com';var ifr = document.createElement('iframe');ifr.src = 'http://cn.a.com/b.html';ifr.style.display = 'none';document.body.appendChild(ifr);ifr.onload = function(){ //获取Frame对象文档内容 var doc = ifr.contentDocument || ifr.contentWindow.document; // 在这里操纵b.html alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeVaue);};
cn.a.com b.html页面
document.domain = 'a.com';
2.跨域方法二:jsonp
这里就不讨论jsonp和json的区别了,就像java和javascript名字相似,其实质是两种东西。
jsonp其实就是利用script标签不受同源策略限制为出发点的。像下面这样
//jquery CDN服务,引用不同域文件完全不受同源策略限制<script src="//cdn.bootcss.com/jquery/3.1.1/core.js"></script>
我们先构建jsonp的雏形
A域下有个a.html,B域下有个b.js
A域下a.html页面内容为:
<script type="text/script"> function info(my){ console.log(my.info); }</script><script type="text/script" src="B/b.js"></script>
B域下b.js的内容为:
info({info:"kingboss"});
结果为:kingboss
所以jsonp的实质是,另一个域下的文件传递一个callback执行函数,函数名与原域所定义的函数名相同。
当然世界是多变的,代码是活的,所以我们可以动态的创建script标签,引入可变的src地址
A域下a.html页面内容改为:
<script type="text/script"> function info(my){ console.log(my.info); } function addScript(src){ var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function(){ addScript("B/b.js"); }</script>
B域下b.js的内容不变:
info({info:"kingboss"});
有人就会问了,加入B域下的文件不知道A域下的函数名怎么办?简单,那就让A域下的文件告诉B就ok了,具体的告知方式就是在url部添加callback参数
A域下a.html页面内容改为:
<script type="text/script"> function info(my){ console.log(my.info); } function addScript(src){ var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function(){ addScript("B/b.js?callback=info"); }</script>
B域下的文件根据callback参数动态生成执行函数
jquery的jsonp实现上面的例子
<script src="//cdn.bootcss.com/jquery/3.1.1/core.js"></script><script type="text/javascript"> $(function(){ $.ajax({ type: "get", async: false, url: "B/b.js", dataType: "jsonp", jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback) jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据 success: function(my){ console.log(my.info) }, error: function(){ alert('fail'); } }); })</script>
注意:jsonp只支持get请求,原因不是很清楚
3.跨域方法三:location.hash
前面我们讲过document.domain只适用于主域名相同,子域名不同的情况,那么主域名也不同呢?又该怎么办。所以就有了进阶版,location.hash传值方法。
什么是location.hash,其实它是js用来管理内部地址的对象,内容为:
方法:利用location.hash进行传值,选择其传值的理由是改变hash指不会刷新页面。A域下a.html通过创建iframe指向B域下b.html,由于不同域,所以B域下会创建A域的a1.html(代理页面),代理页面a1.html和a.html同属一个域,因此可以修改。缺点:数据完全暴露在url中,容量也有限制
逻辑图
A域下 a.html
<script type="text/javascript"> function startRequest(){ var ifr = document.createElement('iframe'); ifr.style.display = 'none'; ifr.src = 'B/b.html#data'; document.body.appendChild(ifr); } function checkHash() { try { //获取hash传入的data值 var data = location.hash ? location.hash.substring(1) : ''; if (console.log) { console.log('Now the data is '+data); } } catch(e) {}; } setInterval(checkHash, 2000);</script>
B域下 b.html
<script type="text/script"> switch(location.hash){ case '#paramdo': callBack(); break; case '#paramset': //do something…… break; } function callBack(){ try { parent.location.hash = 'somedata'; } catch (e) { // ie、chrome的安全机制无法修改parent.location.hash, // 所以要利用一个中间的B域下的代理iframe var ifrproxy = document.createElement('iframe'); ifrproxy.style.display = 'none'; ifrproxy.src = 'A/a1.html#somedata'; // 注意该文件在A域下 document.body.appendChild(ifrproxy); } }</script>
A域下 a1.html
<script type="text/javascript"> //因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值 parent.parent.location.hash = self.location.hash.substring(1);</script>
4.跨域方法四:window.name
先了解一下什么是window.name,以及它有什么特性。window.name方法传值其实和location.hash类似,也依靠代理文件实现。共需要三份文件,A域下的a.html;B域下的b.html;A域下的a1.html(空代理文件)
B域下的b.html
<script type="text/javascript"> window.name = 'data'; // 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右</script>
A域下的a.html
<script type="text/javascript"> var state = 0, //动态地创建iframe iframe = document.createElement('iframe'), iframe.src = 'B/b.html'; document.body.appendChild(iframe); loadfn = function() { if (state === 1) { var data = iframe.contentWindow.name; // 读取数据 alert(data); //弹出'data' } else if (state === 0) { //改变iframe的location指向代理文件 iframe.contentWindow.location = "A/a1.html"; // 设置的代理文件 } }; //兼容,能力检测 if (iframe.attachEvent) { iframe.attachEvent('onload', loadfn); } else { iframe.onload = loadfn; } //销毁iframe iframe.contentWindow.document.write('');//文档内容清空 iframe.contentWindow.close();//关闭子窗口 document.body.removeChild(iframe);//去除tag</script>
疑问:
1.什么是window.name?
解释:name 属性可设置或得到窗口的名称,其值为字符串;该名称是在 open() 方法创建窗口时指定的或者使用一个 frame 标记的 name 属性指定的,默认情况下 name 属性值是为空的。窗口的 name 属性可以用于a或form标签的 target 属性值,这样表示超链接文档或表单提交结果应该显示于指定 name 的窗口或框架中。
特点是:name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。—->这也解释了为什么A域的代理文件可以访问到B域的window.name
2.什么是contentWindow属性?
contentWindow : 兼容各个浏览器,可取得子窗口的 window 对象。
contentDocument : Firefox 支持,> ie8 的ie支持。能够以 HTML 对象来返回 iframe 中的文档。可以通过所有标准的 DOM 方法来处理被返回的document对象
解决了上面的疑惑,用图来呈现此逻辑
结束语
虽然跨域有很多种方法,但是要折中,比如引入iframe本身就对网页优化有一定的影响,还有location.hash的安全漏洞等问题。所以不要滥用。
- javascript基础--跨域
- javaScript基础
- JAVASCRIPT 基础
- JavaScript基础
- JAVASCRIPT基础
- JavaScript 基础
- javascript基础
- javascript基础
- JavaScript 基础
- JavaScript基础
- javascript基础
- JavaScript基础
- javascript基础
- javascript基础
- Javascript基础
- JavaScript基础
- JavaScript基础
- javascript基础
- Android屏幕适配
- MongoDB3.0版本特性
- Linux下Mysql安装(源码包)
- Oracle中的sysdate
- Linux内核错误码与错误指针
- javascript基础--跨域
- spring使用context:property-placeholder载不进属性问题
- 关于噪波
- Android Freeline加速编译App方案 使用和总结
- Java 单例 双重检查锁的正确姿势
- Application context和Activity context的区别及应用
- SSM框架---Spring注解@Component、@Repository、@Service、@Controller区别
- 2015年33期Java/Spring/Struts2/web/基础/就业班视频
- 西北