美文网首页
跨域方式具体实现

跨域方式具体实现

作者: 饥人谷_Leon | 来源:发表于2017-07-29 21:45 被阅读0次

    一.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>
    

    参考文章

    相关文章

      网友评论

          本文标题:跨域方式具体实现

          本文链接:https://www.haomeiwen.com/subject/zjyclxtx.html