首頁  >  文章  >  web前端  >  Javascript幾個跨域方式

Javascript幾個跨域方式

高洛峰
高洛峰原創
2017-02-28 14:35:291113瀏覽

在客戶端程式語言中如javascript,同源策略規定跨域之間的腳本是隔離的,一個域的腳本不能存取和操作另外一個域的絕大部分屬性和方法。只有當兩個域具有相同的協議,相同的主機,相同的連接埠時,我們就認定他們是相同的域。可是在實際開發中我們經常需要取得其他域的資源,這個時候各種不同的跨域資源方式就各顯神通了,今天主要來總結一下工作中常用的幾種跨域方式,以備查詢。

1.window.name

window 物件的name屬性是一個很特別的屬性,當在 frame 中載入新頁面時,name 的屬性值依舊保持不變。那麼我們可以在頁面A中用iframe載入其他域的頁面B,而頁面B中用JavaScript把需要傳遞的資料賦值給window.name,iframe加載完成之後,此時name 屬性值可被獲取到,以訪問Web 服務所傳送的訊息。但 name 屬性僅對相同網域的 frame 可存取。這意味著為了存取 name 屬性,當遠端 Web 服務頁面被載入後,必須導航 frame 回到原始網域。即頁面A修改iframe的位址,將其變成同域的一個位址,然後就可以唸出window.name的值了。一旦 name 屬性獲得,銷毀 frame 。這個方式非常適合單向的資料請求,而且協定簡單、安全。

頁面B(www.jesse.com/data.html)程式碼如下:

#
<script type="text/javascript">
window.name = 'I was there!';
// 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右
// 数据格式可以自定义,如json、字符串
</script>

頁面A(www.jack.com/ index.html)程式碼如下:

<script type="text/javascript">
var state = 0,
  iframe = document.createElement('iframe'),
  loadfn = function() {
    if (state === 1) {
      var data = iframe.contentWindow.name; // 读取数据
      console.log(data); //弹出'I wasthere!'
      (function(){
        //获取数据以后销毁这个iframe。
        iframe.contentWindow.document.write('');
        iframe.contentWindow.close();
        document.body.removeChild(iframe);
      })();
    } else if (state === 0) {
      state = 1;
      // 设置的代理页面使其回原始域
      iframe.contentWindow.location = "http://www.jack.com/proxy.html"; 
    }
  };
iframe.src = 'http://www.jesse.com/data.html';
if (iframe.attachEvent) {
  iframe.attachEvent('onload', loadfn);
} else {
  iframe.onload = loadfn;
}
document.body.appendChild(iframe);
</script>

2.具備src的標籤

雖然瀏覽器預設禁止了跨網域訪問,但並不禁止在頁面中用標籤的src屬性引用其他網域的檔案。根據這一點,可以方便地透過建立具有src屬性的節點方法來實現完全跨域的通訊。使用這種原理的跨域方式有以下幾種:

動態建立script

例如我要從網域A的頁面pageA載入網域B的數據,那麼在網域B的頁面pageB中我以JavaScript的形式宣告pageA需要的數據,然後在pageA中用script標籤把pageB載入進來,那麼pageB中的腳本就會得以執行。

pageA(www.jack.com/index.html)程式碼如下:

#
function getData(data){
  //这里是对获取的数据的相关操作
  console.log(data);
  //数据获取到后移除创建的script标签
  document.body.removeChild(originData);
}
var originData = document.createElement('script');
originData.src = 'http://www.jesse.com/data.js';
originData.setAttribute("type", "text/javascript");
document.body.appendChild(originData);

pageB(www.jesse.com/data. js)程式碼如下:

getData('这里是远程跨域获取的数据');//数据格式可以自定义,如json、字符串

jsonp

在用$.ajax()取得遠端資料時,如果是跨網域資源則可以使用jsonp方法,以前一直以為jsonp是ajax的一種,後來才明白他們根本就不是一回事。 ajax是以xhr方式請求資料的,而jsonp是以script方式請求資料的,而這個就是跟上面的動態建立script方式一樣。

pageA(www.jack.com/index.html)程式碼如下:

#
$.ajax({
  //JSONP不支持POST方式
  type:"GET",
  url:"http://www.jesse.com/data.php",
  dataType:"jsonp",
  //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
  jsonpCallback:"getData",
  success: function(data){
    console.log(data);
  },
  error: function(){
    console.log('fail');
  }
})

pageB(www.jesse.com /data.js)程式碼如下:

<?php
  $callback = $_GET[&#39;callback&#39;];//得到回调函数名,这里是getData
  $data = array(&#39;a&#39;,&#39;b&#39;,&#39;c&#39;);//要返回的数据
  echo $callback.&#39;(&#39;.json_encode($data).&#39;)&#39;;//输出
?>

3.document.domain

對於主域相同而子域不同的例子,可以設定document.domain的辦法來解決。 具體的做法是可以在http://www.php.cn/和http://www.php.cn/兩個檔案中分別加上document.domain = "a.com";然後透過a.html檔案中建立一個iframe,去控制iframe的contentDocument,這樣兩個js檔案之間就可以「互動」了。當然這種辦法只能解決主域相同而二級網域不同的情況

www.a.com上的a.html

document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://script.a.com/b.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
  var doc = ifr.contentDocument || ifr.contentWindow.document;
  // 在这里操纵b.html
  alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
};

#script.a.com上的b.html

document.domain = 'a.com';

#4.跨網域資源共享(CORS)

原理:跨來源資源共享(CORS)定義跨域存取的機制,可以讓AJAX實現跨域存取。 CORS允許一個網域上的網路應用程式向另一個網域提交跨域AJAX請求。實現此功能非常簡單,只需由伺服器發送回應標頭即可。它是透過客戶端+服務端協作聲明的方式來確保請求安全的。服務端會在HTTP請求頭中增加一系列HTTP請求參數(例如Access-Control-Allow-Origin等),來限制哪些網域的請求和哪些請求類型可以接受,而客戶端在發起請求時必須宣告自己的來源(Orgin),否則伺服器將不予處理,如果客戶端不作聲明,請求甚至會被瀏覽器直接攔截都到不了服務端。服務端收到HTTP請求後會進行域的比較,只有同域的請求才會處理。

pageA(www.jack.com/index.html)程式碼如下:

#
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
  if(xhr.readyState === 4 && xhr.status === 200){
    console.log(xhr.responseText);
  }
};
xhr.open("get","http://www.jesse.com/data.php");
xhr.send(null);

pageB(www.jesse.com/data. php)程式碼如下:

<?php
  header("Access-Control-Allow-Origin: http://www.php.cn/");//与简单的请求相同
  header("Access-Control-Allow-Methods: GET, POST");//允许请求的方法
  header("Access-Control-Max-Age: 3628800"); //将这个请求缓存多长时间
  $data = array(&#39;a&#39;,&#39;b&#39;,&#39;c&#39;);//要返回的数据
  echo json_encode($data);//输出
?>

5.window.postMesage 不常用

window.postMessage(message,targetOrigin) 方法是html5新引進的特性,可以使用它來向其它的window物件發送訊息,無論這個window物件是屬於同源或不同來源,目前IE8+、FireFox、Chrome、Opera等瀏覽器都已經支援window.postMessage方法。

pageA(www.jack.com/index.html)程式碼如下:

#
<iframe id="proxy" src="http://www.jesse.com/index.html" onload="postMsg()" style="display: none"></iframe>
<script type="text/javascript">
var obj = {
  msg: 'hello world'
}

function postMsg() {
  var iframe = document.getElementById('proxy');
  var win = iframe.contentWindow;
  win.postMessage(obj, 'http://www.jesse.com');
}
</script>

pageB(www.jesse.com/data.php)代码如下:
<script type="text/javascript">
window.onmessage = function(e) {
  console.log(e.data.msg + " from " + e.origin);
}
</script>

6. location. hash 不常用

pageA(www.jack.com/index.html)程式碼如下:

#
function startRequest() {
  var ifr = document.createElement('iframe');
  ifr.style.display = 'none';
  ifr.src = 'http://www.jesse.com/b.html#sayHi'; //传递的location.hash 
  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, 5000);
window.onload = startRequest;

pageA(www.jack.com /proxy.html)程式碼如下:

parent.parent.location.hash = self.location.hash.substring(1);

#pageB(www.jesse.com/b.html)程式碼如下:

function checkHash() {
  var data = '';
  //模拟一个简单的参数处理操作
  switch (location.hash) {
    case '#sayHello':
      data = 'HelloWorld';
      break;
    case '#sayHi':
      data = 'HiWorld';
      break;
    default:
      break;
  }
  data && callBack('#' + data);
}

function callBack(hash) {
  // ie、chrome的安全机制无法修改parent.location.hash,所以要利用一个中间的www.a.com域下的代理iframe
  var proxy = document.createElement('iframe');
  proxy.style.display = 'none';
  proxy.src = 'http://www.jack/c.html' + hash; // 注意该文件在"www.jack.com"域下
  document.body.appendChild(proxy);
}
window.onload = checkHash;

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持PHP中文網。

更多Javascript幾種跨域方式相關文章請關注PHP中文網!


#
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn