常见跨域方法原理及其用例

一、常见跨域方法

1) JSONP跨域 需要目标服务器配合一个callback函数
2) AJAX跨域 CORS
3) 使用window.name+iframe来进行跨域
4) window.postMessage:跨文档通信 API(Cross-document messaging)
5) 跨子域:修改document.domain
6) 通过Nginx反向代理
7) WebSocket

 

二、原理及其用例

JSONP跨域:

原理:
<script>可跨域请求资源,json格式被原生 JavaScript支持,客户端与服务器端配合
客户端动态定义并实现一个函数,将函数添加到请求的目标 URL中,通过创建 <script src="URL">跨域请求资源
服务器端接受到请求,获取添加在请求 URL中的函数,将需要的数据以参数的形式传入获取到的函数中并返回
客户端获取到带有参数(需要的数据)的函数,执行该函数(客户端已经定义并实现了该函数),处理数据
用例:

客户端代码:

<!DOCTYPE HTML>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>JSONP</title>
  <style>
    body, input, select, button, h1 {
      font-size: 28px;
      line-height:1.7;
    }
</style>
</head>
<body>

  <h1>员工查询</h1>
  <label>请输入员工编号:</label>
  <input type="text" id="keyword" />
  <button id="search">查询</button>
  <p id="searchResult"></p>
  <script>
    /**
     * 原理:
     * <script>可跨域请求资源,json格式被原生 JavaScript支持,客户端与服务器端配合
     * 客户端动态定义并实现一个函数,将函数添加到请求的目标 URL中,通过创建 <script src="URL">跨域请求资源
     * 服务器端接受到请求,获取添加在请求 URL中的函数,将需要的数据以参数的形式传入获取到的函数中并返回
     * 客户端获取到带有参数(需要的数据)的函数,执行该函数(客户端已经定义并实现了该函数),处理数据
     */
    function myJSONP(url) {

      //创建一个十位数的随机数
      var randomNumber = Math.random().toString().substring(2, 12);
      // 生成 cbname(jsonp请求用到的回调函数,后面会添加到URL中)
      var cbname = "callbackName" + randomNumber;

      // 将 cbname函数挂载到 myJSONP函数上(即 myJSONP里面有一个 cbname函数)
      var myJSONP_cbname = "myJSONP." + cbname;
      //实现 cbname回调函数
      myJSONP[cbname] = function (response) {
        try {
          // var data=JSON.parse(data); //返回的数据已经是json格式,所以不用转换,否则错误
          if (response.success)
            document.querySelector("#searchResult").innerHTML=response.msg;//请求成功
          else
            document.querySelector("#searchResult").innerHTML="出现错误:"+response.msg;//请求失败
        } finally {
          //请求完成,删除函数以及移除脚本
          delete myJSONP[cbname];
          script.parentNode.removeChild(script);
        }
      };

      //创建script用于发送请求
      var script = document.createElement("script");
      //将 myJSONP里面的 cbname函数添加到URL中
      if (url.indexOf("?") === -1) {
        url += "?callback=" + myJSONP_cbname;
      } else {
        url += "&callback=" + myJSONP_cbname;
      }
      //将脚本的 src指向请求URL,然后将脚本添加到页面中,触发http请求
      script.src = url;
      document.body.appendChild(script);
    }

    document.querySelector("#search").onclick=function(){
      // jsonp跨域请求(模拟跨域请求)
      // jsonp.html 在浏览器中打开的地址为: http://localhost/jsonp.html
      // jsonp.php 服务器地址为: http://127.0.0.1:80/jsonp.php 
      var url="http://127.0.0.1:80/jsonp.php?number="+document.querySelector("#keyword").value;
      myJSONP(url);
    }

  </script>
</body>
</html>

服务器端代码:

<?php
//设置页面内容是html编码格式是utf-8
// header("Content-Type: text/plain;charset=utf-8"); 
header("Content-Type: application/json;charset=utf-8"); 
//header("Content-Type: text/xml;charset=utf-8"); 
//header("Content-Type: text/html;charset=utf-8"); 
//header("Content-Type: application/javascript;charset=utf-8"); 

//定义一个多维数组,包含员工的信息,每条员工信息为一个数组
$staff = array
    (
        array("name" => "洪七", "number" => "101", "sex" => "男", "job" => "总经理"),
        array("name" => "郭靖", "number" => "102", "sex" => "男", "job" => "开发工程师"),
        array("name" => "黄蓉", "number" => "103", "sex" => "女", "job" => "产品经理")
    );

//判断如果是get请求,则进行搜索;如果是POST请求,则进行新建
//$_SERVER是一个超全局变量,在一个脚本的全部作用域中都可用,不用使用global关键字
//$_SERVER["REQUEST_METHOD"]返回访问页面使用的请求方法
if ($_SERVER["REQUEST_METHOD"] == "GET") {
    search();
} elseif ($_SERVER["REQUEST_METHOD"] == "POST"){
    create();
}

//通过员工编号搜索员工
function search(){    
    $jsonp = $_GET["callback"];
    //检查是否有员工编号的参数
    //isset检测变量是否设置;empty判断值为否为空
    //超全局变量 $_GET 和 $_POST 用于收集表单数据
    if (!isset($_GET["number"]) || empty($_GET["number"])) {
        echo $jsonp . '({"success":false,"msg":"参数错误"})';
        return;
    }
    //函数之外声明的变量拥有 Global 作用域,只能在函数以外进行访问。
    //global 关键词用于访问函数内的全局变量
    global $staff;
    //获取number参数
    $number = $_GET["number"];    
    $result = $jsonp . '({"success":false,"msg":"没有找到员工。"})';
    
    //遍历$staff多维数组,查找key值为number的员工是否存在,如果存在,则修改返回结果
    foreach ($staff as $value) {
        if ($value["number"] == $number) {
            $result = $jsonp . '({"success":true,"msg":"找到员工:员工编号:' . $value["number"] .                
                            ',员工姓名:' . $value["name"] . 
                            ',员工性别:' . $value["sex"] . 
                            ',员工职位:' . $value["job"] . '"})';
            break;
        }
    }
    echo $result;
}

//创建员工
function create(){
    //判断信息是否填写完全
    if (!isset($_POST["name"]) || empty($_POST["name"])
        || !isset($_POST["number"]) || empty($_POST["number"])
        || !isset($_POST["sex"]) || empty($_POST["sex"])
        || !isset($_POST["job"]) || empty($_POST["job"])) {
        echo '{"success":false,"msg":"参数错误,员工信息填写不全"}';
        return;
    }
    //TODO: 获取POST表单数据并保存到数据库
    
    //提示保存成功
    echo '{"success":true,"msg":"员工:' . $_POST["name"] . ' 信息保存成功!"}';
}

?>

运行结果:

 

AJAX跨域 CORS:

原理:跨域是浏览器行为(浏览器阻止跨域),服务器不存在跨域问题,客户端发出请求到服务器,服务器端通过设置相关信息(允许哪些域、允许哪些头部、允许哪些数据类型、是否允许发送cookie等),服务器返回响应信息(包含前面设置的相关信息)给客户端,客户端接接受响应,看到这些信息,允许对应的跨域请求。
CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)更详细的内容:详情点击这里(阮一峰的这篇博客讲得很清楚)

用例:
AJAX跨域之CORS "跨域资源共享"(Cross-origin resource sharing)GET请求之简单请求:
客户端代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    body, input, select, button, h1 {
      font-size: 28px;
      line-height:1.7;
    }
  </style>
</head>

<body>
  <h1>查询员工</h1>

  <label>请输入员工编号:</label>
  <input type="text" id="keyword" />
  <button id="search">查询</button>
  <p id="searchResult"></p>
<script> function handlerResponse(response){ var response=JSON.parse(response); if (response.success) document.querySelector("#searchResult").innerHTML=response.msg;//请求成功 else document.querySelector("#searchResult").innerHTML="出现错误:"+response.msg;//请求失败 } document.querySelector("#search").onclick=function(){ // CORS跨域请求(模拟跨域请求) // AjaxCORS.html 在浏览器中打开的地址为: http://localhost/AjaxCORS.html // AjaxCORS.php 服务器地址为: http://127.0.0.1:80/AjaxCORS.php var url="http://127.0.0.1:80/AjaxCORS.php?number="+document.querySelector("#keyword").value; ajaxGET(url,handlerResponse); } function ajaxGET(url,callback){ var xhr=new XMLHttpRequest(); xhr.open("GET",url); xhr.send(null); xhr.onreadystatechange=function(){ if(xhr.readyState==4 && xhr.status==200){ callback(xhr.responseText); } } } </script> </body> </html>

服务器端代码:

<?php
//设置页面内容是html编码格式是utf-8
// header("Content-Type: text/plain;charset=utf-8"); 
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Methods:POST,GET');
header('Access-Control-Allow-Credentials:true'); 
header("Content-Type: application/json;charset=utf-8"); 
//header("Content-Type: text/xml;charset=utf-8"); 
//header("Content-Type: text/html;charset=utf-8"); 
//header("Content-Type: application/javascript;charset=utf-8"); 

//定义一个多维数组,包含员工的信息,每条员工信息为一个数组
$staff = array
    (
        array("name" => "洪七", "number" => "101", "sex" => "男", "job" => "总经理"),
        array("name" => "郭靖", "number" => "102", "sex" => "男", "job" => "开发工程师"),
        array("name" => "黄蓉", "number" => "103", "sex" => "女", "job" => "产品经理")
    );

//判断如果是get请求,则进行搜索;如果是POST请求,则进行新建
//$_SERVER是一个超全局变量,在一个脚本的全部作用域中都可用,不用使用global关键字
//$_SERVER["REQUEST_METHOD"]返回访问页面使用的请求方法
if ($_SERVER["REQUEST_METHOD"] == "GET") {
    search();
} elseif ($_SERVER["REQUEST_METHOD"] == "POST"){
    create();
}

//通过员工编号搜索员工
function search(){
    //检查是否有员工编号的参数
    //isset检测变量是否设置;empty判断值为否为空
    //超全局变量 $_GET 和 $_POST 用于收集表单数据
    if (!isset($_GET["number"]) || empty($_GET["number"])) {
        echo '{"success":false,"msg":"参数错误"}';
        return;
    }
    //函数之外声明的变量拥有 Global 作用域,只能在函数以外进行访问。
    //global 关键词用于访问函数内的全局变量
    global $staff;
    //获取number参数
    $number = $_GET["number"];
    $result = '{"success":false,"msg":"没有找到员工。"}';
    
    //遍历$staff多维数组,查找key值为number的员工是否存在,如果存在,则修改返回结果
    foreach ($staff as $value) {
        if ($value["number"] == $number) {
            $result = '{"success":true,"msg":"找到员工:员工编号:' . $value["number"] . 
                            ',员工姓名:' . $value["name"] . 
                            ',员工性别:' . $value["sex"] . 
                            ',员工职位:' . $value["job"] . '"}';
            break;
        }
    }
    echo $result;
}?>

 运行结果:

 

AJAX跨域之CORS "跨域资源共享"(Cross-origin resource sharing)POST请求之非简单请求:

客户端代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AjaxCORS</title>
  <style>
    body, input, select, button, h1 {
      font-size: 28px;
      line-height:1.7;
    }
  </style>
</head>
<body>
  <h1>新建员工</h1>
  <label>请输入员工姓名:</label>
  <input type="text" id="staffName" /><br>
  <label>请输入员工编号:</label>
  <input type="text" id="staffNumber" /><br>
  <label>请选择员工性别:</label>
  <select id="staffSex">
    <option></option>
    <option></option>
  </select><br>
  <label>请输入员工职位:</label>
  <input type="text" id="staffJob" /><br>
  <button id="save">保存</button>
  <p id="createResult"></p>

  <script>
    function handlerResponse(response){
      var response=JSON.parse(response);
      if (response.success)
        document.querySelector("#createResult").innerHTML=response.msg;//请求成功
      else
        document.querySelector("#createResult").innerHTML="出现错误:"+response.msg;//请求失败
    }
    
    document.querySelector("#save").onclick=function(){
      // CORS跨域请求(模拟跨域请求)
      // AjaxCORS.html 在浏览器中打开的地址为: http://localhost/AjaxCORS.html
      // AjaxCORS.php 服务器地址为: http://127.0.0.1:80/AjaxCORS.php
      var url="http://127.0.0.1:80/AjaxCORS.php";
            var data= {
                "name": document.querySelector("#staffName").value, 
                "number": document.querySelector("#staffNumber").value, 
                "sex": document.querySelector("#staffSex").value, 
                "job": document.querySelector("#staffJob").value
      };
      data=JSON.stringify(data); 
      ajaxPOST(url,data,handlerResponse);
    }

  function ajaxPOST(url,data,callback){
    var xhr=new XMLHttpRequest();
    xhr.open("POST",url);
    xhr.setRequestHeader("Content-type","application/json");
    xhr.send(data);
    xhr.onreadystatechange=function(){
      if(xhr.readyState==4 && xhr.status==200){ 
        callback(xhr.responseText);
      }
    }
  }

  </script>
</body>
</html>

服务器端代码:

<?php
//设置页面内容是html编码格式是utf-8
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Headers:content-type');
// header('Access-Control-Allow-Methods:POST,GET,OPTION');
// header('Access-Control-Allow-Credentials:true'); 
// header("Content-Type: text/plain;charset=utf-8"); 
header("Content-Type: application/json;charset=utf-8"); 

//定义一个多维数组,包含员工的信息,每条员工信息为一个数组
$staff = array
    (
        array("name" => "洪七", "number" => "101", "sex" => "男", "job" => "总经理"),
        array("name" => "郭靖", "number" => "102", "sex" => "男", "job" => "开发工程师"),
        array("name" => "黄蓉", "number" => "103", "sex" => "女", "job" => "产品经理")
    );

//判断如果是get请求,则进行搜索;如果是POST请求,则进行新建
//$_SERVER是一个超全局变量,在一个脚本的全部作用域中都可用,不用使用global关键字
//$_SERVER["REQUEST_METHOD"]返回访问页面使用的请求方法
if ($_SERVER["REQUEST_METHOD"] == "GET") {
    search();
} elseif ($_SERVER["REQUEST_METHOD"] == "POST"){
    create();
}//创建员工
function create(){
  //判断信息是否填写完全  
  $data=json_decode(file_get_contents('php://input'),true);  //转换成数组  
    if (!$data["name"] || !$data["number"]    || !$data["sex"]    || !$data["job"]) {
        echo '{"success":false,"msg":"参数错误,员工信息填写不全"}';
        return;
    }
  //TODO: 获取POST表单数据并保存到数据库
      
    //提示保存成功
    echo '{"success":true,"msg":"员工:' . $data["name"] . ' 信息保存成功!"}';
}
?>

运行结果:

首先是预检请求 ,使用 OPTION方法

然后是正式请求,使用 POST方法:

 即:非简单请求分为 ,"预检"请求 + 简单请求。

 

使用window.name+iframe来进行跨域:
原理:
通过浏览器的 window.name 属性实现跨域请求(每个浏览器窗口都有一个 window.name属性)
原理:无论是否同源,只要在 “同一个窗口里”,前一个网页设置了这个属性,后一个网页就可以读取它,如页面 A中
有一个 iframe,iframe.src指向页面 B,若页面 B设置了 window.name属性,那么页面 A中的那个 iframe就能获
取到页面 B中的 window.name(虽然 A中的 iframe能读取到 B中的 window.name属性,但是由于iframe在页面 A中,
而 iframe.src指向页面 B,浏览器会因为页面 A与 iframe不同源而阻止获取,因此还需要设置 iframe.src指向页面 A所在的域)
用例:
页面 a.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <!-- 假设这个页面是域 www.aaa.com 下面的页面 A.html -->
  <title>a.html</title>
</head>
<body>
  <h2>domainA/a.html</h2>  
  <button id="btn">get_data_by_iframe_window.name</button>
  <h3 id="data"></h3>
  <script>      

    //获取按钮绑定事件,添加一个 iframe
    var btn=document.getElementById("btn");
    btn.onclick=function(){
      var ifr=document.createElement("iframe");
      //模拟跨域请求
      // a.html 在浏览器中打开的地址为: http://localhost/a.html
      // b.html 需要请求的页面地址为: http://127.0.0.1:80/b.html
      ifr.src="http://127.0.0.1/b.html";
      //添加 iframe到当前页面中,并设置为不可见
      ifr.style.display = 'none';
      var body=document.getElementsByTagName("body")[0];
      body.appendChild(ifr);
      
      //iframe.src会触发 iframe.onload事件,因此使用标记来判断 iframe.src是否已经更改
      var flag=true;
      ifr.onload=function(){                
        if(flag){     
          flag=false;        
          //为了不让浏览器阻止不同源获取window.name属性的值,这里需要设置 iframe与当前页面在同一个域
          //(也可以指向其他页面,只要与创建当前 iframe的页面在同一个域都可以)
          ifr.src="http://localhost/a.html";
        }
        else{
          //contentWindow属性返回<iframe>元素的Window对象,由此获取 b.html页面中设置的 window.name属性的值
          document.querySelector("#data").innerText=ifr.contentWindow.name;          
          //获取数据完成,删除 iframe
          body.removeChild(ifr);   
        }
      }
    }    
    
    /**
* 不太清楚?????? * 假设当前页面为 domainA/p.html,里面有 iframe.src=domianA/a.html * 如果开始时候 iframe.src=domainB/b.html,后来 iframe.src=domianA/a.html时, * 那么必须是先执行完 iframe.src=domainB/b.html这就语句后面的代码后,iframe才会属于域 domainA, * 而在执行完 iframe.src=domainB/b.html这就语句后面的代码前,iframe依然属于域 domainB。 * * 如:假设在页面 domainA/p.html中 属于域 domainA,iframe在 p.html中创建 * * 首先 * iframe.src=domainB/b.html * 没更换 iframe.src 之前执行完其他代码 现在属于域 domainB * * 然后 * iframe.src=domianA/a.html 现在属于域 domainB * 每更换 iframe.src 之前执行完其他代码 现在属于域 domainA *
*/ </script> </body> </html>

页面 b.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>b.html</title>
</head>
<body>
  <script>
    //b.html中设置 window.name的值(需要传输的数据)
    window.name = "我是需要传输的数据,来自 domainB/b.html";
  </script>
</body>
</html>

运行结果:

 

window.postMessage:跨文档通信 API(Cross-document messaging)

原理:

* HTML5为了解决跨域问题引入了一个全新的API:跨文档通信 API(Cross-document messaging)。
* 这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。

* 使用方法: otherWindow.postMessage(message, targetOrigin, [transfer]);
* otherWindow:
* 其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames
* message:
* 将要发送到其他 window的数据。
* targetOrigin:
* 通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI
* 只有当目标窗口与 targetOrigin的源完全相同时消息才能被成功发送,只要协议、主机名、端口其中一项不同消息都不会被发送
* (这个参数就显得尤为重要,必须保证它的值与这条包含密码的信息的预期接受者的origin属性完全一致,来防止密码被恶意的第三方截获)
* [transfer]:
* 是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

* 父窗口和子窗口都可以通过message事件,监听对方的消息。
* message事件的事件对象event,提供以下三个属性。
* event.source:记录调用 window.postMessage()方法的窗口信息
* event.origin: 表示调用 window.postMessage()方法时,调用页面的当前状态
* event.data: 要发送到其他 window的数据
 
用例:
页面 a.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>a.html</title>
</head>
<body>
  <script>    
    /**
     * 本例中:模拟跨域
     * a.html :  http://localhost/a.html
     * b.html :  http://127.0.0.1/b.html
     */
    
      var popup=window.open("http://127.0.0.1/b.html","title b.html");
      // targetOrigin为:http://127.0.0.1 协议: http 主机名: 127.0.0.1 端口号: 默认(80) 
      // b.html中的域为:http://127.0.0.1 协议: http 主机名: 127.0.0.1 端口号: 默认(80) 
      // 可见目标窗口与 targetOrigin的源完全相同
      popup.postMessage("aaaaaa 在a.html中 通过 postMessage 发送","http://127.0.0.1/b.html"); 
    
    //监听子窗口信息
    window.addEventListener("message",function(event){
      //event.origin: 表示调用 window.postMessage()方法时,调用页面的当前状态
      //在本例中,这里监听的是 b.html中 evnet.source.postMessage()事件,event.source.postMessage()的当前状态还是属于域 http://127.0.0.1
      //console.log(event.origin); //输出: http://127.0.0.1
      if (event.origin !== 'http://127.0.0.1') return;
      console.log(event.data);
    });

    </script>
</body>
</html>

页面 b.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>b.html</title>
</head>
<body>  
  <script>
    //监听父窗口信息
    window.addEventListener("message",function(event){     
      //event.origin: 表示调用 window.postMessage()方法时,调用页面的当前状态
      //在本例中,这里监听的是 a.html中 popup.postMessage()事件,popup.postMessage()的当前状态还是属于域 http://localhost
      //console.log(event.origin); //输出: http://localhost
      if (event.origin !== 'http://localhost') return;      
      console.log(event.data);
      
      //event.source:记录调用 window.postMessage()方法的窗口信息
      //在本例中,这里监听的是 a.html中 popup.postMessage()事件,因此这里 event.source记录的是 a.html页面窗口的信息
      // targetOrigin为:http:localhost 协议: http 主机名: localhost 端口号: 默认(80) 
      // a.html中的域为:http:localhost 协议: http 主机名: localhost 端口号: 默认(80) 
      // 可见目标窗口与 targetOrigin的源完全相同
      event.source.postMessage("bbbbbb 在b.html中 通过 postMessage 发送","http:localhost");
    });

    //当然也可以使用 window.opener发送信息
    window.opener.postMessage("bbbbbb 在b.html中 通过 window.opener.postMessage 发送","http:localhost");
  </script>
</body>
</html>

运行结果:

 

跨子域:修改document.domain

原理:两个文档上一层级的域名相同,下一层级(或该层级以下的域名不同),将两个文档的 document.domain都修改为上一层级的域名(这样他们的 document.domain就一样了)

用例:

      页面一 http://a.test.com/a.html  
        域为: http://a.test.com
        设置该页面的 document.domain=test.com  
        设置 document.cookie= "hello=world"
      页面二 http://b.test.com/b.html  
        域为: http://b.test.com
        设置该页面的 document.domain=test.com  
        这里 console.log(document.cookie) 输出结果包含 "hello=world"

 

通过反向代理 (Reverse Proxy)

原理:反向代理(Reverse Proxy)方式是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器;并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。假设有:页面A 、 服务器B(有A想要的资源,但不同域)、代理服务器P(跟A同一个域),页面 A将请求发送给代理服务器(同一个域),由代理服务器P向服务器B获取所需要的数据(跨域是浏览器阻止跨域,服务器不存在跨域问题),然后代理服务器将获取的数据返回给页面 A(同一个域)

用例:无

 

WebSocket 跨域

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

用例:无

 

参考:

MDN 官网:https://developer.mozilla.org

阮一峰博客-浏览器同源政策及其规避方法:http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html

阮一峰博客-跨域资源共享 CORS 详解:http://www.ruanyifeng.com/blog/2016/04/cors.html

 

 

posted @ 2018-11-28 23:50  ノ→_→(←_←  阅读(669)  评论(0编辑  收藏  举报