跨域方式具体实现

一.CORS

1.CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

2.两种请求方式

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

只要同时满足以下两大条件,就属于简单请求。

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

浏览器对这两种请求的处理,是不一样的。

3基本流程

  • 简单请求: 正常发送Ajax请求=>浏览器检测到此请求为跨域请求自动增加一个origin字段=>服务器根据这个值决定是否同意这次请求=>浏览器得到回应,根据返回的头信息没有包含Access-Control-Allow-Origin字段判断本次CORS请求是否成功
GET /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Host: api.alice.com
Accept-Language: en-USConnection: keep-alive
User-Agent: Mozilla/5.0...

上面的头信息中,Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。

  • 非简单请求:非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。
    非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。
OPTIONS /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

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

二.JSONP

JSONP的实现思路
1.前端创建script标记,设置src,添加到head中(可以往body中添加)
2.后台返回一个js变量jsonp,这个jsonp就是请求后的JSON数据
3.回调完成后删除script标记(还有一些清理工作如避免部分浏览器内存泄露等)
范例:

//服务器代码
var http = require('http');  
var urllib = require('url');  
  
var port = 10011;  
var data = {'name': 'jifeng', 'company': 'taobao'};  
  
http.createServer(function(req, res){  
  var params = urllib.parse(req.url, true);  
  console.log(params);  
  if (params.query && params.query.callback) {  
    //console.log(params.query.callback);  
    var str =  params.query.callback + '(' + JSON.stringify(data) + ')';//jsonp  
    res.end(str);  
  } else {  
    res.end(JSON.stringify(data));//普通的json  
  }       
}).listen(port, function(){  
  console.log('server is listening on port ' + port);    
})  

<html>    
<head>    
  <script src="http://code.jquery.com/jquery-latest.js"></script>    
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">    
</head>    
<body>    
<script type="text/javascript">    
function get_jsonp() {    
  $.getJSON("http://10.232.36.110:10011?callback=?",    //浏览器端代码,jQuery实现
  function(data) {  
    $('#result').val('My name is: ' + data.name);    
  });    
}    
</script>    
<a href="javascript:get_jsonp();">Click me</a><br />    
<textarea id="result" cols="50" rows="3"></textarea>    
</body>    
</html>  

三.postmanage

HTML5中最酷的新功能之一就是 跨文档消息传输Cross Document Messaging。下一代浏览器都将支持这个功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。

otherWindow.postMessage(message, targetOrigin);
otherWindow: 对接收信息页面的window的引用。可以是页面中iframe的contentWindow属性;window.open的返回值;通过name或下标从window.frames取到的值。
message: 所要发送的数据,string类型。
targetOrigin: 用于限制otherWindow,“*”表示不作限制
a.com/index.html中的代码:

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
    var ifr = document.getElementById('ifr');
    var targetOrigin = 'http://b.com';  // 若写成'http://b.com/c/proxy.html'效果一样
                                        // 若写成'http://c.com'就不会执行postMessage了
    ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

b.com/index.html中的代码:

<script type="text/javascript">
    window.addEventListener('message', function(event){
        // 通过origin属性判断消息来源地址
        if (event.origin == 'http://a.com') {
            alert(event.data);    // 弹出"I was there!"
            alert(event.source);  // 对a.com、index.html中window对象的引用
                                  // 但由于同源策略,这里event.source不可以访问window对象
        }
    }, false);
</script>

参考文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容