之前很少将跨域作为一个重点来考虑,一直以为只要服务器设置了cors就可以解决问题,但面试过程中遇到了很多跨域的问题,不得不说,这块知识确实需要梳理一下,以下便从跨域的原因、方法和方法的局限性几个方面来研究
出于安全的考虑,浏览器设置了一个同源策略,主要有两个限制:
+ 无法通过ajax的方法获取不同源中的文档
+ 浏览器中不同域的框架之间是不能进行js的交互操作的
cors(cross-origin resource sharing)跨域资源共享,服务器在返回请求内容时候,将请求头设置允许跨域,那么该请求是允许被跨域请求的
[服务端]
var var http = require('http')
http.createServer((req,res)=>{
res.setHeader('Access-Control-Allow-Origin','http://localhost.com')
res.setHeader('Access-Control-Allow-Method','GET,PUT,POST,DELETE,OPTION')
res.setHeader('Access-Control-Allow-Header','Content-Type')
res.setHeader('status','200 ok')
res.write('Hello world!')
res.end()
}).listen(8889)
[客户端]
jsonp,即json+padding,主要有服务器生成一个function包裹着json
[服务端]get请求/jsonp?name=xx这个接口返回的数据
function parseJsonp({
name:xx,
content:xx_content
})
[客户端]
function loadScript(url){
var $script = document.createElement('script')
$script.setAttribute('src',url)
var $head = document.getElementsByTagName('head')[0]
$head.appendChild($script)
}
function parseJsonp(json){
// do something
}
loadScript('/jsonp?name=xxx')
不同框架间可以获取window对象,但是无法获取相应的属性和方法,例如:
页面和iframe框架不同域,无法通过页面中的js代码来获取iframe中的属性和方法。要想跨域操作页面,可以采用document.domain,将这两个页面的document.domain设置成相同域名。但要注意的是,document.domain的设置是有限制,只能设置为自身或更高一级的父域,且主域必须相同
代码如下:
+ 2.在页面 http://example.com/b.html 中设置document.domain
代码如下:
在一个窗口(window)的生命周期中,窗口载入的所有的页面共享一个window.name,每个页面对window.name都有读写的权限,window.name是持久在一个窗口载入的所有页面中的
假设有三个页面
a.com/index.html
a.com/empty.html
b.com/index.html
(1)在a.com/index.html页面中潜入一个隐藏的iframe,设置src为b.com/index.html
(2)b.com/index.html载入后,设置window.name,然后再使用location.href = ‘a.com/empty.html’,跳转到和iframe页面外同域的页面
(3)在a.com/index.html页面中,就可以通过iframe,找到其window.name来获取这个值
注意:实际操作中一般都是监听iframe的第二次onload事件,然后用iframe.contentWindow.name获取跨域数据
HTML5中的window.postMessage(message,targetOrigin)是一个安全的、基于事件的消息API,以下先解释下几个概念
+ 源窗口:往新窗口发送数据的窗口。
①源窗口可以是全局的window
②文档窗口中的iframe(iframe.documentWindow)
③javascript打开的弹窗(window.open())
④当前文档的父窗口(window.parent)
④打开当前文档的窗口(window.opener
[源窗口] http://www.a.com/index.html
[目标窗口] http://www.b.com/index.html