zoukankan      html  css  js  c++  java
  • 跨域知识总结

    一、概述

    1.1 什么是同源

           只要协议、域名、端口有任何一个不同,都被当作是不同的域。

    URL 说明 是否允许通信
    http://www.a.com/a.js
    http://www.a.com/b.js
    同一域名下 允许
    http://www.a.com/lab/a.js
    http://www.a.com/script/b.js
    同一域名下不同文件夹 允许
    http://www.a.com:8000/a.js
    http://www.a.com/b.js
    同一域名,不同端口 不允许
    http://www.a.com/a.js
    https://www.a.com/b.js
    同一域名,不同协议 不允许
    http://www.a.com/a.js
    http://70.32.92.74/b.js
    域名和域名对应ip 不允许
    http://www.a.com/a.js
    http://script.a.com/b.js
    主域相同,子域不同 不允许
    http://www.a.com/a.js
    http://a.com/b.js
    同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问)
    http://www.cnblogs.com/a.js
    http://www.a.com/b.js
    不同域名 不允许

     

    1.2 限制范围

      目前,如果非同源,共有三种行为受到限制:

    1. Cookie、LocalStorage 和 IndexDB 无法读取。
    2. DOM 无法获得。
    3. AJAX 请求不能发送。

      

    1.3  其他

    1. 如果是协议端口造成的跨域问题“前台”是无能为力的;
    2. 在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。

        (“URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。)

    二、主域相同子域不同

    2.1 document.domain

      这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 无法通过这种方法。我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同

    iframe

      在页面http://www.damonare.cn/a.html 中设置document.domain:

    <iframe id = "iframe" src="http://damonare.cn/b.html" onload = "test()"></iframe>
    <script type="text/javascript">
        document.domain = 'damonare.cn';//设置成主域
        function test(){
            alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象
        }
    </script>

      在页面http://damonare.cn/b.html 中也设置document.domain:

    <script type="text/javascript">
        document.domain = 'damonare.cn';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同
    </script>

    Cookie

      Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是,两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享 Cookie。

      假设A网页为http://w1.example.com/a.html,B网页为http://w2.example.com/b.html,那么只要设置相同的document.domain,两个网页就可以共享Cookie。

    //A页面
    <script>
        document.domain = 'example.com';  //设置domain
        document.cookie = "test1=hello";  //设置cookie
    </script>
    
    //B页面
    <script>
        document.domain = 'example.com';  //设置domain
        var allCookie = document.cookie;  //读取cookie
    </script>

    三、完全不同源

    irame

    3.1   location.hash

      因为父窗口可以对iframe进行URL读写,iframe也可以读写父窗口的URL,URL有一部分被称为hash,就是#号及其后面的字符,它一般用于浏览器锚点定位,Server端并不关心这部分,应该说HTTP请求过程中不会携带hash,所以这部分的修改不会产生HTTP请求,但是会产生浏览器历史记录。

      此方法的原理就是改变URL的hash部分来进行双向通信。每个window通过改变其他 window的location来发送消息(由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于父窗口域名下的一个代理iframe),并通过监听自己的URL的变化来接收消息。

      这个方式的通信会造成一些不必要的浏览器历史记录,而且有些浏览器不支持onhashchange事件,需要轮询来获知URL的改变,最后,这样做也存在缺点,诸如数据直接暴露在了url中,数据容量和类型都有限等。

    • cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html页面
    • cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据
    • 同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一旦有变化则获取获取hash值
      注:由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe

      a.com下的文件cs1.html文件:

    function startRequest(){
        var ifr = document.createElement('iframe');
        ifr.style.display = 'none';
        ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';
        document.body.appendChild(ifr);
    }
     
    function checkHash() {
        try {
            var data = location.hash ? location.hash.substring(1) : '';
            if (console.log) {
                console.log('Now the data is '+data);
            }
        } catch(e) {};
    }
    setInterval(checkHash, 2000);

      cnblogs.com域名下的cs2.html:

    
    //模拟一个简单的参数处理操作
    switch(location.hash){
        case '#paramdo':
            callBack();
            break;
        case '#paramset':
            //do something……
            break;
    }
    
    function callBack(){
        try {
            parent.location.hash = 'somedata';
        } catch (e) {
            // ie、chrome的安全机制无法修改parent.location.hash,
            // 所以要利用一个中间的cnblogs域下的代理iframe
            var ifrproxy = document.createElement('iframe');
            ifrproxy.style.display = 'none';
            ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata';    // 注意该文件在"a.com"域下
            document.body.appendChild(ifrproxy);
        }
    }

    3.2   window.name

      window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。 

      这种方法的优点是,window.name容量很大,可以放置非常长的字符串;缺点是必须监听子窗口window.name属性的变化,影响网页性能。

      1) 创建a.com/cs1.html

      2) 创建a.com/proxy.html,并加入如下代码:

    <head>
      <script>
      function proxy(url, func){
        var isFirst = true,
            ifr = document.createElement('iframe'),
            loadFunc = function(){
              if(isFirst){
                ifr.contentWindow.location = 'http://a.com/cs1.html';
                isFirst = false;
              }else{
                func(ifr.contentWindow.name);
                ifr.contentWindow.close();
                document.body.removeChild(ifr);
                ifr.src = '';
                ifr = null;
              }
            };
        ifr.src = url;
        ifr.style.display = 'none';
        if(ifr.attachEvent) ifr.attachEvent('onload', loadFunc);
        else ifr.onload = loadFunc;
     
        document.body.appendChild(iframe);
      }
    </script>
    </head>
    <body>
      <script>
        proxy('http://www.baidu.com/', function(data){
          console.log(data);
        });
      </script>
    </body>

      3) 在b.com/cs1.html中包含:

    <script>
        window.name = '要传送的内容';
    </script>

    3.3   window.postMessage

      HTML5引入了一个全新的API:跨文档通信 API(Cross-document messaging)。高级浏览器Internet Explorer 8+, chrome,Firefox , Opera 和 Safari 都将支持这个功能。这个功能主要包括接受信息的”message”事件和发送消息的”postMessage”方法,允许跨窗口通信,不论这两个窗口是否同源。

      otherWindow.postMessage(message, targetOrigin);

    • otherWindow:指目标窗口,也就是给哪个window发消息,是 window.frames 属性的成员或者由 window.open 方法创建的窗口
    • message: 是要发送的消息,类型为 String、Object (IE8、9 不支持)
    • targetOrigin: 接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。
    //窗口http://aaa.com向子窗口http://bbb.com发消息
    var popup = window.open('http://bbb.com', 'title');
    popup.postMessage('Hello World!', 'http://bbb.com');
    
    //子窗口向父窗口发送消息
    window.opener.postMessage('Nice to see you', 'http://aaa.com');

    message事件的事件对象event,提供以下三个属性。

    • event.source:发送消息的窗口
    • event.origin: 消息发向的网址
    • event.data: 消息内容 
    if (typeof window.addEventListener != 'undefined') {  
        window.addEventListener('message', onmessage, false);  
    } else if (typeof window.attachEvent != 'undefined') {  
        //for ie  
        window.attachEvent('onmessage', onmessage);  
    }  
    
    var onmessage = function (event) {  
    
        console.log(event.data);
    }; 

      

      子窗口通过event.source属性引用父窗口,然后发送消息。

    window.addEventListener('message', receiveMessage);
    function receiveMessage(event) {
        event.source.postMessage('Nice to see you!', '*');
    }

      event.origin属性可以过滤不是发给本窗口的消息。

    window.addEventListener('message', receiveMessage);
    function receiveMessage(event) {
        if (event.origin !== 'http://aaa.com') return;
        if (event.data === 'Hello World') {
            event.source.postMessage('Hello', event.origin);
        } else {
            console.log(event.data);
        }
    }

    3.4   localStorage

      通过window.postMessage,读写其他窗口的 LocalStorage 也成为了可能。 

      主窗口写入iframe子窗口的localStorag。

    //子窗口将父窗口发来的消息,写入自己的LocalStorage。
    window.onmessage = function(e) {
        if (e.origin !== 'http://bbb.com') {
            return;
        }
        var payload = JSON.parse(e.data);
        localStorage.setItem(payload.key, JSON.stringify(payload.data));
    };
    
    //父窗口发送消息的代码
    var win = document.getElementsByTagName('iframe')[0].contentWindow;
    var obj = { name: 'Jack' };
    win.postMessage(JSON.stringify({key: 'storage', data: obj}), 'http://bbb.com'); 

    加强版的子窗口接收消息的代码如下。

    window.onmessage = function(e) {
      if (e.origin !== 'http://bbb.com') return;
      var payload = JSON.parse(e.data);
      switch (payload.method) {
        case 'set':
          localStorage.setItem(payload.key, JSON.stringify(payload.data));
          break;
        case 'get':
          var parent = window.parent;
          var data = localStorage.getItem(payload.key);
          parent.postMessage(data, 'http://aaa.com');
          break;
        case 'remove':
          localStorage.removeItem(payload.key);
          break;
      }
    };

    加强版的父窗口发送消息代码如下。

    var win = document.getElementsByTagName('iframe')[0].contentWindow;
    var obj = { name: 'Jack' };
    // 存入对象
    win.postMessage(JSON.stringify({key: 'storage', method: 'set', data: obj}), 'http://bbb.com');
    // 读取对象
    win.postMessage(JSON.stringify({key: 'storage', method: "get"}), "*");
    window.onmessage = function(e) {
        if (e.origin != 'http://aaa.com') return;
        // "Jack"
        console.log(JSON.parse(e.data).name);
    };

    AJAX

    3.5  JSONP

       JSONP是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。

      缺点:

    1. 它只支持GET请求而不支持POST等其它类型的HTTP请求
    2. 它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
    3. 调用失败的时候不会返回各种HTTP状态码。
    4. 安全性低。

      原理:当我们通过script标签请求时,后台就会根据相应的参数(json,handleResponse)来生成相应的json数据。最后这个返回的json数据(代码)就会被放在当前js文件中被执行,至此跨域通信完成

    function addScriptTag(src) {
      var script = document.createElement('script');
      script.setAttribute("type","text/javascript");
      script.src = src;
      document.body.appendChild(script);
    }
    
    window.onload = function () {
      addScriptTag('http://example.com/ip?callback=foo');
    }
    
    function foo(data) {
      console.log('Your public IP address is: ' + data.ip);
    };

      上面代码通过动态添加<script>元素,向服务器example.com发出请求。注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于JSONP是必需的。

      从JQery 1.2以后,就开始支持JSONP的调用。在另外的一个域名中指定好回调函数名称,你就可以用下面的形式来就加载JSON数据。 

    $.getJSON(url + "&callbak=?", function(data)  {  
        alert("Symbol:" + data.symbol + ", Price:" + data.price);  
    }); 

      jQuery会在window对象中加载一个全局的函数,当代码插入时函数执行,执行完毕后就会被移除。同时jquery还对非跨域的请求进行了优化,如果这个请求是在同一个域名下那么他就会像正常的Ajax请求一样工作。

       上例中我们在动态插入到页面的代码中使用了静态的json数据,虽然完成了依次JSONP返回,但仍不是JSONP服务,因为不支持在URL中定义回调函数名称。下面是一个将其变成JSONP服务的一个方法。

      首先我们来定义接口的规范,http://www.mydomain.com/jsonp/ticker?symbol=IBM&amp;callback=showPrice。symbol是请求条件,callback是回调函数名称。

    //JQuery JSONP Support  
    var url = "http://www.mydomain.com/api/suggest.php?symbol=IBM&callback=?";  
    $.getJSON(url, function(data){  
        alert("Symbol:" + data.symbol + ", Price:" + data.price);  
    }); 

    在suggest.php中

    $jsondata = "{symbol:'IBM', price:120}";  
    echo $_GET['callback'].'('.$jsondata.')';

    3.6  WebSocket

      WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。 

    只有在支持web socket协议的服务器上才能正常工作。

    var iframe = document.getElementById('iframe');
    var data = '';
     
    iframe.onload = function() {
        iframe.onload = function(){
            data = iframe.contentWindow.name;
        }
        iframe.src = 'about:blank';
    };

      浏览器发出的WebSocket请求的头信息

    GET /chat HTTP/1.1
    Host: server.example.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
    Sec-WebSocket-Protocol: chat, superchat
    Sec-WebSocket-Version: 13
    Origin: http://example.com 

      上面代码中,有一个字段是Origin,表示该请求的请求源(origin),即发自哪个域名。

      正是因为有了Origin这个字段,所以WebSocket才没有实行同源政策。因为服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就会做出如下回应。

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
    Sec-WebSocket-Protocol: chat

    3.7  CORS

       CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS允许任何类型的请求。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

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

      浏览器将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-urlencodedmultipart/form-datatext/plain

      凡是不同时满足上面两个条件,就属于非简单请求。

    3.7.1简单请求

    ( 1 ) 基本流程

      对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。

      下面是一个例子,浏览器发现这次跨源AJAX请求是简单请求,就自动在头信息之中,添加一个Origin字段。

        GET /cors HTTP/1.1
        Origin: http://api.bob.com
        Host: api.alice.com
        Accept-Language: en-US
        Connection: keep-alive
        User-Agent: Mozilla/5.0...

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

      如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequestonerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。

      如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。

        Access-Control-Allow-Origin: http://api.bob.com
        Access-Control-Allow-Credentials: true
        Access-Control-Expose-Headers: FooBar
        Content-Type: text/html; charset=utf-8

      上面的头信息之中,有三个与CORS请求相关的字段,都以Access-Control-开头。

       <1>Access-Control-Allow-Origin

      该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

      <2>Access-Control-Allow-Credentials

      该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。

      <3>Access-Control-Expose-Headers

      该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值。

    3.2 withCredentials 属性

      上面说到,CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。

        Access-Control-Allow-Credentials: true

      另一方面,开发者必须在AJAX请求中打开withCredentials属性。

        var xhr = new XMLHttpRequest();
        xhr.withCredentials = true;

      否则,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。

      但是,如果省略withCredentials设置,有的浏览器还是会一起发送Cookie。这时,可以显式关闭withCredentials

        xhr.withCredentials = false;

      需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。

    3.7.2、非简单请求

    ( 1 )预检请求

      非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUTDELETE,或者Content-Type字段的类型是application/json

      非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

      浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

    下面是一段浏览器的JavaScript脚本。

        var url = 'http://api.alice.com/cors';
        var xhr = new XMLHttpRequest();
        xhr.open('PUT', url, true);
        xhr.setRequestHeader('X-Custom-Header', 'value');
        xhr.send();

      上面代码中,HTTP请求的方法是PUT,并且发送一个自定义头信息X-Custom-Header

      浏览器发现,这是一个非简单请求,就自动发出一个"预检"请求,要求服务器确认可以这样请求。下面是这个"预检"请求的HTTP头信息。

        OPTIONS /cors HTTP/1.1
        Origin: 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...

      "预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。

      除了Origin字段,"预检"请求的头信息包括两个特殊字段。

       < 1 >Access-Control-Request-Method

      该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT

       < 2 >Access-Control-Request-Headers

      该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header

    ( 2 )预检请求的回应

      服务器收到"预检"请求以后,检查了OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。

        HTTP/1.1 200 OK
        Date: Mon, 01 Dec 2008 01:15:39 GMT
        Server: Apache/2.0.61 (Unix)
        Access-Control-Allow-Origin: http://api.bob.com
        Access-Control-Allow-Methods: GET, POST, PUT
        Access-Control-Allow-Headers: X-Custom-Header
        Content-Type: text/html; charset=utf-8
        Content-Encoding: gzip
        Content-Length: 0
        Keep-Alive: timeout=2, max=100
        Connection: Keep-Alive
        Content-Type: text/plain

      上面的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示http://api.bob.com可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。

        Access-Control-Allow-Origin: *

      如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。

        XMLHttpRequest cannot load http://api.alice.com.
        Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.

      服务器回应的其他CORS相关字段如下。

        Access-Control-Allow-Methods: GET, POST, PUT
        Access-Control-Allow-Headers: X-Custom-Header
        Access-Control-Allow-Credentials: true
        Access-Control-Max-Age: 1728000

      

       < 1 >Access-Control-Allow-Methods

      该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。

      < 2 >Access-Control-Allow-Headers

      如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。

      < 3 >Access-Control-Allow-Credentials

      该字段与简单请求时的含义相同。

      < 4 >Access-Control-Max-Age

      该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

    ( 3 )浏览器的正常请求和回应

      一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。

    下面是"预检"请求之后,浏览器的正常CORS请求。

        PUT /cors HTTP/1.1
        Origin: http://api.bob.com
        Host: api.alice.com
        X-Custom-Header: value
        Accept-Language: en-US
        Connection: keep-alive
        User-Agent: Mozilla/5.0...  

      上面头信息的Origin字段是浏览器自动添加的。

      下面是服务器正常的回应。

        Access-Control-Allow-Origin: http://api.bob.com
        Content-Type: text/html; charset=utf-8

      上面头信息中,Access-Control-Allow-Origin字段是每次回应都必定包含的。

    3.7.3、与JSONP的比较

      CORS与JSONP的使用目的相同,但是比JSONP更强大。

      JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

  • 相关阅读:
    【故障处理】ORA-12162: TNS:net service name is incorrectly specified (转)
    android studio 编程中用到的快捷键
    java时间格式串
    android Error occurred during initialization of VM Could not reserve enough space for object heap Could not create the Java virtual machine.
    linux安装vmware
    x1c 2017 安装mint18的坑——grub2
    x1c2017 8G版 win linux的取舍纠结记录
    python的try finally (还真不简单)
    kafka+docker+python
    json文件不能有注释
  • 原文地址:https://www.cnblogs.com/surahe/p/6042122.html
Copyright © 2011-2022 走看看