1. 程式人生 > >常見跨域方法原理及其用例

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

一、常見跨域方法

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"] . ' 資訊儲存成功!"}';
}

?>

執行結果:

 

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">
  <meta http-equiv="Content-Type" content="application/json; charset=utf-8">  
  <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
     * 執行完其他程式碼             現在屬於域 domainB
     * 
     * 然後
     * iframe.src=domianA/a.html 現在屬於域 domainB
     * 執行完其他程式碼             現在屬於域 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與代理伺服器在同一個域,頁面 A將請求傳送給代理伺服器(同一個域),由代理伺服器到頁面 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