为什么会出现跨域问题我们想象一下以下几种情况:我们开了一个天猫,登录了自己的账号,然后我们又开了一个天猫商品,我们不需要重新登录直接购买商品,因为两个网页同源,可以共享登录相关的cookie或localStorage数据;如果您在使用支付宝或网银的同时打开了一个未知的网页,如果该网页可以访问您的支付宝或网银页面的信息,将会造成严重的安全问题。如果未知网站是黑客的工具,他可以利用它发起CSRF攻击。显然浏览器不允许这样的事情发生;想必你也同时登录了几个qq账号,如果你同时打开各自的qq空间浏览器,会有一个小模式,就是会打开另一个窗口打开第二个的空间qq账号。为了解决不同域名相互访问数据带来的不安全问题,Netscape提出了一个众所周知的安全策略——同源策略,即来自同一“源”的数据可以自由访问,但来自不同域名的数据不同的来源是相互排斥的。无法访问。同源政策是显而易见的。在上面的第一个和第三个例子中,不同的天猫店铺和qq空间同源,可以共享登录信息。为了区分不同qq的登录信息,qq重新开了一个窗口,因为浏览器的不同窗口无法共享信息。在第二个例子中,支付宝、网上银行和未知网站不是同源的,因此它们不能相互访问信息。如果硬要请求数据,会提示异常:No'Access-Control-Allow-Origin'headerispresentontherequestedresource。因此不允许访问Origin'null'。那么什么是同源请求呢?同源请求要求请求的资源页面和请求的页面满足三个相同点:相同的协议,相同的主机,相同的端口,简单理解:/*下面两个数据不是同源的,因为协议不同*/http://www.abc123。com.cn/item/a.jshttps://www.abc123.com.cn/item/a.js/*以下两个数据不是同源的,因为域名不同*/http://www.abc123.com。cn/item/a.jshttp://www.abc123.com/item/a.js/*以下两个数据不是同一来源,因为主机名不同*/http://www.abc123.com.cn/item/a.jshttp://item.abc123.com.cn/item/a.js/*以下两个数据不是同一来源,因为协议不同*/http://www.abc123.com.cn/item/a.jshttp://www.abc123.com.cn:8080/item/a.js/*以下两个数据非同源,域名和ip视为异源*这里要注意ip和域名替换不是同源的*假设www.abc123.com.cn解析的ip是195.155.200.134*/http://www.abc123.com.cn/http://195.155.200.134//*以下两个数据同源*//*这是同源*/http://www.abc123.com.cn/source/a.htmlhttp://www.abc123.com.cn/item/b.jsHTTP简单请求与非简单请求http请求满足以下条件时称为简单请求,否则为非简单请求:请求方法为HEAD之一,GET,和POST,并且HTTP头信息不超过以下字段:AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-TypeContent-Type取值仅限于application/x-www-form-urlencoded、multipart/form-data、text/plain非简单请求前会发送一个OPTION预请求发送,如果跨域操作返回405(MethodNotAllowed)错误,服务器需要允许OPTION请求HTTP跨域访问处理方法及适用条件JSOP适用条件:请求的GET接口需要支持jsonp使用权。这里需要强调的是,jsonp并不是Ajax的一部分,它只是将url放到script标签中实现数据传输,并不受同源策略的限制。由于通用库也会将其与Ajax封装在一起,由于与Ajax的根不一样,这里不再赘述。下面是jsonp的例子:window.jsonpCallback=console.log;varJSONP=document.createElement("script");JSONP.src="http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13122222222&t="+Math.random()+"&callback=jsonpCallback";;document.body.appendChild(JSONP);后端支持jsonp模式(Nodejs)varquerystring=require('querystring');varhttp=require('http');varserver=http.createServer();server.on('request',function(req,res){varparams=qs.parse(req.url.split('?')[1]);varfn=params.callback;//jsonp返回设置res.writeHead(200,{'Content-Type':'text/javascript'});res.write(fn+'('+JSON.stringify(params)+')');res.end();});server.listen('8080');console.log('Serverisrunningatport8080...');document.domain适用条件:host仅在不同服务器的情况下,域名本身应该相同。www.dom.com和w1.dom.com需要从同一来源访问。可以将document.domain设置为dom.com来解决这个问题。document.domain='dom.com';比如我要开发一个浏览器插件,发现腾讯视频页面有iframe本身是跨域的,无法获取到iframe的DOM对象。但是域名部分相同,可以用这种方法解决。注意:如果要设置成完全不同的域名,肯定会报同源错误,注意使用范围!内嵌iframe的适用条件:在host中只有server不同的情况下,域名本身要相同。有了上面的例子,就不难理解这个方法了。严格来说,这并不是一种新的方法,而是对之前方法的扩展。通过设置document.domain,同一个域名下不同服务器名的页面可以访问数据,但是值得注意的是这个数据访问不是相互的,外部页面可以访问iframe内部的数据,但是iframe不能访问外部数据。location.hash适用条件:iframe与其宿主页面通信。#和完成的url中的以下部分是哈希。这部分可以修改,完成iframe和host之间的直接数据传递。下面演示iframe页面(B.html)向宿主(A.html)传输数据,反之亦然://A.htmldata=['book','map','shelf','knife'];setTimeout(()=>{location.hash=window.encodeURIComponent(data.join('/'));},1000);//B.htmlwindow.parent.onhashchange=function(e){vardata=window.decodeURIComponent(e.newURL.split('#')[1]).split('/');控制台日志(数据);//["book","map","shelf","knife"]}*注意反向传输数据时要使用window。parent.location.hashwindow.name适用条件:宿主页面和iframe之间的通信窗口对象有一个name属性,它有一个特点:即在窗口的生命周期内,所有页面(iframe)加载的window都是共享一个window.name,每个页面都有对window.name的读写权限,window.name在一个window加载的所有页面中都是持久化的,不会在加载新页面的地方重新加载。这样就可以在iframe中获取window中编辑window.name,但是这个过程缺少监控,宿主页面(A.html)和iframe页面(B.html)不知道对方什么时候修改value://A.htmlsetTimeout(()=>{window.parent.name="what!";},2000);//B.htmlsetTimeout(()=>{console.log(window.name);//什么!},2500);postMessage适用条件:postMessage是H5提出的一种消息交换机制,解决了iframe之间不能互通的问题,也可以跨窗口互通。语法如下://在www.siteA.com中发送消息//@message{any}要发送的数据(注意:旧浏览器只支持字符串类型)//@targetOrigin{string}指定要发送的域接收数据,只有它指定的域可以接收消息,如果是"*"则没有域限制//transfer{any}与消息一起发送并转移所有权window.postMessage(message,targetOrigin,[transfer]);//在另一个页面接受参数window.onmessage=console.log;这里不说第三个参数,因为你这辈子可能用不到它。而targetOrigin最好不要使用“*”,除非你想让所有的页面都收到你的消息。您将使用的场景(iframe):、
