Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

跨域的几种实现方法 #21

Open
incuisting opened this issue Sep 7, 2017 · 0 comments
Open

跨域的几种实现方法 #21

incuisting opened this issue Sep 7, 2017 · 0 comments

Comments

@incuisting
Copy link
Owner

CORS

实现CORS需要浏览器和服务器的共同协作。对于前端开发者来说,CORS通信与同源的AJAX在代码方面没有差别。浏览器一旦发现AJAX请求跨源,就会自动添加附加一些请求头信息,有时候还会多出一次附加的请求,但用户不会察觉。
因此,CORS通信的关键就在于后端代码的实现,只要服务器实现了CORS接口,就可以跨源通信。

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

  • 简单请求
    • 请求方法是以下三种方法之一:
      • HEAD
      • GET
      • POST
    • HTTP的头信息不超出以下几种字段:
      • Accept
      • Accept-Language
      • Content-Language
      • Last-Event-ID
      • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
  • 非简单请求
    • 凡是不同时满足上面两个条件,就属于非简单请求

两种请求浏览器对他们的处理方式也不一样

简单请求处理流程

(发起AJAX请求) ==> (浏览器发现请求为跨源AJAX简单请求)==>(浏览器自动在头信息里添加Origin字段) ==>(服务器根据收到的Origin字段来决定是否同意这次请求)==> (浏览器得到回应,根据返回的头信息没有包含Access-Control-Allow-Origin字段判断本次CORS请求是否成功)

Origin字段: 用来说明,本次请求来自哪个源(协议 + 域名 + 端口)

非简单请求处理流程

(向自动发出预检请求)==> (服务器回应预检请求)==> (服务器同意则会返回一个带Access-Control-Allow-Origin头信息的HTTP回应) ==> (浏览器判断预检请求是否被允许) ==>(如果预检请求被通过,以后每次的非简单请求,就都和简单请求一样)


代码示例:

** 简单请求 **

  var url = 'http://api.a.com/cors';// 在本站地址http://localhost:8080
  var xhr = new XMLHttpRequest();
  xhr.open('get',url,true);
  xhr.send()

非简单请求

  var url = 'http://api.a.com/cors';// 在本站地址http://localhost:8080
  var xhr = new XMLHttpRequest();
  xhr.open('put',url,true); //发起的非GET POST HEAD 的请求
  xhr.send()

参考文章

JSONP

利用HTML中script标签可以引入其他域下的js的特性,来实现跨域访问接口。后端配合返回如下格式的数据:

dosomething({
  ’aa‘:'bb',
  ‘cc’:{....}
})

因为是script标签的请求,所以返回的数据会作为javascript去执行。那么我们只用再定义一个dosomething函数就可以了,他的参数就是返回的json数据。

<script type="text/javascript">
   function dosomething(json){
     //处理JSONP放回的数据
   }
</script>
  <script src="http://api.a.com/cors?callback=dosomething"></script>

修改document.domain

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

  <div class='main' >
    <input type="text">
  </div>
<iframe  src="http://a.example.com/b.html"></iframe>
<script type="text/javascript">
    document.domain = 'example.com';//设置成主域
  document.querySelector('.main input').addEventListener('input',function(){
  console.log(this.value);
  window.frames[0].document.querySelector('input').value = this.value;//对调用的iframe进行dom操作
})
</script>

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

 <div class='main' >
    <input id='input' type="text">
  </div>
<script type="text/javascript">
document.domain = 'example.com';//设置成主域
     document.querySelector('#input').addEventListener('input',function(){
  window.parent.document.querySelector('input').value = this.value;//因为是用iframe调用了b.html所用用window.parent来获得父级页面
})
</script>

两个在同源下不同域的两个页面通过document.domain可以实现主域名一样下两个子域名网站做iframe嵌套的时候进行相互操作dom。

PostMassage

window.postMessage() 方法可以安全地实现跨源通信。

语法

示例

页面http://b.example.com/b.html 中设置PostMessage

 <div class='main' >
    <input type="text">
  </div>
<iframe  src="http://a.example.com/b.html"></iframe>
<script type="text/javascript">
  document.querySelector('.main input').addEventListener('input',function(){
  console.log(this.value);
  window.frames[0].postMessage(this.value.'');// * 表示没有指定域名,也可以把*指定成固定的域名
})
window.addEventListener('message',function(e){ //监听message事件,可以监听别人给他发的内容,然后拿出来使用
  document.querySelector('.main input').value = e.data
})
</script>

message事件还有如下属性:

安全问题

如果你不希望从其他网站接收message,那么就不要为message事件添加任何事件侦听器。 这是一个完全万无一失的方式来避免安全问题。如果你用了,那么在监听message事件的时候一定要做origin的验证。如下:

function receiveMessage(event)
{  if (event.origin !== "http://example.org")
    return;
}
window.addEventListener("message", receiveMessage, false);

这样你就可以保证你接受到的信息是来自你希望收到的网站

使用场景:

1.页面和其打开的新窗口的数据传递
2.多窗口之间消息传递
3.页面与嵌套的iframe消息传递

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant