大前端之路----跨域

跨域

[写在前面]

  之前很少将跨域作为一个重点来考虑,一直以为只要服务器设置了cors就可以解决问题,但面试过程中遇到了很多跨域的问题,不得不说,这块知识确实需要梳理一下,以下便从跨域的原因、方法和方法的局限性几个方面来研究

一.原因

  出于安全的考虑,浏览器设置了一个同源策略,主要有两个限制:
+ 无法通过ajax的方法获取不同源中的文档
+ 浏览器中不同域的框架之间是不能进行js的交互操作的

二.方法

1.cors方法

概念

  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)

[客户端]
<script>
  var xhr = new XMLHttpRequest()
  xhr.open("GET","http://anothersite.com/",true)
  xhr.send()
</script>

2.jsonp

概念

  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')
利弊
  • 利处\
      兼容旧版本的浏览器,不需要XMLHttpRequest或ActiveX的支持,并且在请求结束后通过callback的方式来回传数据
  • 弊处\
      只支持GET请求;只支持跨域HTTP请求这种情况,无法解决不同域的两个页面之间如何进行javascript调用的问题

3.document.domain跨子域

概念

  不同框架间可以获取window对象,但是无法获取相应的属性和方法,例如:

<!-- 页面'http://www.example.com/a.html'下 -->
<div>
  <iframe src='http://example.com/b.html'></iframe>
</div>

  页面和iframe框架不同域,无法通过页面中的js代码来获取iframe中的属性和方法。要想跨域操作页面,可以采用document.domain,将这两个页面的document.domain设置成相同域名。但要注意的是,document.domain的设置是有限制,只能设置为自身或更高一级的父域,且主域必须相同

具体实现

代码如下:

<iframe id='iframe' src='http://example.com/b.html' onload='test()'></iframe>
<script>
  document.domain = 'example.com'
  function test(){
    // contentWindow对象相当于iframe中的页面的window对象
    var subWindow = document.getElementById('iframe').contentWindow
    // do something
  }
</script>

+ 2.在页面 http://example.com/b.html 中设置document.domain

代码如下:

<script>
  // 在iframe载入这个页面的时候,设置document.domain,使之与主页面的document.domain相同
  document.domain = 'example.com'
</script>
优弊
  • 利处\
      可以跨页面操作不同域的内容
  • 弊处\
      只适用于不同子域的框架间的交互

4.window.name来进行跨域

概念

  在一个窗口(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获取跨域数据

5.使用HTML5的window.postMessage方法跨域

概念

  HTML5中的window.postMessage(message,targetOrigin)是一个安全的、基于事件的消息API,以下先解释下几个概念
+ 源窗口:往新窗口发送数据的窗口。
①源窗口可以是全局的window
②文档窗口中的iframe(iframe.documentWindow)
③javascript打开的弹窗(window.open())
④当前文档的父窗口(window.parent)
④打开当前文档的窗口(window.opener

  • 目标窗口:数据接收端的页面,接收方窗口有个事件监听器,监听’message‘事件,当然也需要验证消息源是来自哪里
  • window.postMessage接收两个参数:message为将要发送的消息,targetOrigin为目标窗口的源
  • message事件监听函数接收一个参数,event对象,该对象有三个属性:
    ①data:postMessage传过来的数据
    ②origin:执行postMessage的源窗口的源
    ③source:执行postMessage的源窗口的引用
具体实现
[源窗口] http://www.a.com/index.html
<script>
  window.onload = () => {
    var win = window.open('http://www.b.com/index.html')
    win.postMessage('Hello world!', 'http://www.b.com/')
  }
</script>
[目标窗口] http://www.b.com/index.html
<script>
  function getMessage(event){
    var data = event.data
    // do something
  }
  window.onload = () => {
    if(window.addEventListener){
      window.addEventListener('message',getMessage,false)
    }else{
      window.attachEvent('message',getMessage)
    }
  }
</script>
优弊
  • 优处
      可以在不同窗口进行通信
  • 弊处
      ①需要获取window的引用;②IE7-浏览器不支持这种通信方式

6.其他方法

  • url查询字符:eg.localtion.href = ‘www.b.com/index.html?name=value’
  • hash片段:eg.location.href = ‘www.b.com/index.html#params’
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值