js中幾種跨域的方法

js跨域是指經過js在不一樣域之間進行相互通訊或者數據傳輸,只要協議,域名,端口號其中有一個不一樣,就是跨域。下面總結一下我瞭解到的經常使用的跨域方法。javascript

一:經過jsonp跨域

js經過script標籤引入一個外域的資源是不受限制的,jsonp就是利用這個原理,來實現跨域的。html

<script>
    function getPrice(data){
        console.log(data);
    }
</script>
<script type="text/javascript" src="http://wsdetail.b2b.hc360.com/getSupplyPrice?callback=getPrice&bcid=47296567"></script>

callback是先後臺約定的查詢參數,服務器端返回一個能執行的js文件,這個js文件是調用callback對應的參數值即getPrice執行,而且返回對應的數據,咱們能夠在getPrice方法裏面來處理返回的數據,最終返回的結果以下html5

getPrice({
"data":{"priceType":"0","unit":"斤"},
"message":"價格獲取成功!!!",
"state":"1"
 })

jsonp的原理就是這樣,經過Script標籤引入一個js文件,這個js文件加載成功會執行callback對應的指定方法,而且把咱們須要的數據做爲參數傳入,jsonp是須要服務器端配合的。java

$.ajax({
   url:"http://wsdetail.b2b.hc360.com/getSupplyPrice",
   dataType:'jsonp',
   data:{bcid:"47296567"},
   jsonp:'callback',
   jsonpCallback:'getPrice',
   success:function(data){
      console.log(data);
   }
 })

下面是使用jquery的jsonp請求,jsonp只能是get請求,在jquery中jsonpCallback能夠省略不寫,jquery會自動生成一個全局函數替換callback=對應的全局函數,取到數據會自動銷燬這個全局函數;jsonp參數用來替換「callback=?」中的callback
好比 {jsonp:'callbackOnload'},會生成'?callbackOnload=getPrice'傳給服務器端;jquery

二: 使用XMLHttpRequest對象跨域獲取數據

var xhr = new XMLHttpRequest();

    if ('withCredentials' in xhr) {
        xhr.withCredentials = true;
    }

    xhr.open('post', 'https://api.growingio.com/v2/9c75e186a1a30142/web/action?stm=1499731328375', true); //true表示異步請求,若是是false則是同步請求,

    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                var response = xhr.responseText;
                console.log(response)
            }
        }
    };

    xhr.send('data');

XMLHttpRequest最關鍵部分在服務器部分 ,其實不管是否跨域,服務器都是能夠獲取上述請求的。問題的關鍵在於服務器的迴應是否可以返回到瀏覽器。因此在服務器發送迴應的時候,須要添加一個文件頭。這個文件頭的第一個參數是容許跨域,第二個參數是接受跨域的服務,web

Access-Control-Allow-Origin:http://a.text.com

其實與不一樣的XMLHttpRequest還有一個小小的不一樣,卻很重要。同域內的XMLHttpRequest訪問一般只有一次請求,而跨域的XMLHttpRequest有兩次。ajax

第一次XMLHttpRequest請求,其method是OPTIONS,並不是前文定義的POST。這並非由JS代碼控制的,而是瀏覽器來完成的操做。其做用是判斷該請求是否可以被服務器所響應。json

第二次XMLHttpRequest請求才是真正的POST請求,包含了上傳的文件內容。api

這裏只是對 CORS 作一個簡單的介紹,若是想更詳細地瞭解其原理的話,能夠看看下面這篇文章:跨域

阮一峯 跨域資源共享 CORS 詳解

下面介紹三種經過 iframe 跨域與其它頁面通訊的方式。

三: 使用html5的postMessage和onmessage

postMessage 是H5新增的api可使用它來向其它的window對象發送消息,不管這個window對象是屬於同源或不一樣源,目前IE8+、FireFox、Chrome、Opera等瀏覽器都已經支持window.postMessage方法。
第一個參數是要發送的數據,第二個參數是接受消息的域,若是不想限定,可使用通配符'*'

<iframe src="http://b.text.com/index.html" width="200" height="200" id="iframEle" onload="load()"></iframe>
  <script>
      function load() {
              var _window = document.getElementById('iframEle').contentWindow;
      
              _window.postMessage('dfefe','http://b.text.com/index.html');
          }
      
      window.onmessage=function (e) {
              alert(e.data)
      }
  
  </script>

b.text.com域名接受消息的時候須要經過監聽onmessage事件,來獲取傳過來的消息,消息內容存儲在事件對象的data屬性中。

window.onmessage=function (e) {
           e=e||event;
           alert(e.data);
           window.parent.postMessage('1234',"*")
       }

四:經過document.domain跨域

一個頁面嵌入一個外域的iframe頁面,雖然兩個窗體以前能獲取彼此的window對象,可是卻拿不到window上的屬性和方法,例如一個http://a.text.com/index.html頁面嵌入一個http://b.text.com/index.html的iframe

<iframe src="http://b.text.com/index.html" width="200" height="200" id="iframEle" onload="load()"></iframe>
  <script>
      function load() {
          var _window=document.getElementById('iframEle').contentWindow;
          _window.dialog();  
      }
      function parentAlert() {
          alert('我是父窗體的方法')
      }
  
  </script>

嵌入的窗體跟a.text.com的域名不一樣,很明顯是跨域的,雖然能獲取到window對象,可是拿不到b頁面的任何方法和屬性。b頁面能夠用window.parent拿到父窗體,可是也是一樣不能拿到任何方法和屬性。這個時候用document.domain能夠解決這種問題
咱們在b頁面設置document.domain,在a頁面也設置document.domain,document.domain設置也是有限制的,咱們只能把domain設置成自身或者更高一級的父域。主域必須相同

document.domain='text.com';
  function dialog() {
          alert('ifram裏面的方法')
      }
  window.parent.parentAlert()

咱們在a頁面也設置一下domain, document.domain='text.com'; 兩個窗體之間能夠正常通訊了,這就是經過domain跨域獲取數據,這種方式只適合兩個窗體以前,不適合ajax請求;

五:使用 window.name 屬性

window對象有一個name屬性,在一個窗口生命週期內,全部載入的頁面共享這個name屬性,而且都有對這個name的讀寫權限。好比有一個頁面 http://a.text.com/index.html

window.name='我是index頁面設置的name屬性';
  setTimeout(function () {
      window.location.href='http://b.text.com/index.html';
  },3000)

3秒後載入了b頁面,在b頁面咱們獲取window.name,成功的獲取到了index頁面設置的window.name的值,須要注意的是window.name只能是字符串形式,大小2M左右,下面就來看看具體怎樣經過window.name跨域獲取數據

http://my.b.text.com/index.html頁面嵌入一個iframe,

var _iframe=document.createElement('iframe');
     _iframe.src='http://b.text.com/index.html';
     _iframe.style.display='none';
     document.body.appendChild(_iframe);
 
     _iframe.onload=function () {
 
         _iframe.src='about:blank;';
 
         _iframe.onload=function () {
             alert(_iframe.contentWindow.name);
         }
     }

http://b.text.com/index.html頁面設置window.name

window.name='iframe數據'

http://my.b.text.com/index.html頁面請求http://b.text.com/index.html頁面的數據,咱們能夠在頁面創建一個iframe,src指向請求的地址,利用iframe的跨域能力 在請求的頁面設置window.name的值。 可是因爲 my.b.text.com 頁面和該頁面 iframe 的 src 若是不一樣源的話,則沒法操做 iframe 裏的任何東西,因此就取不到 iframe 的 name 值,因此咱們須要在 b.text.com 加載完後從新換個 src 去指向一個同源的 html 文件,或者設置成 'about:blank;'改變iframe的src指向後,這個時候在監聽iframe的onload屬性,就能夠獲取到iframe的window.name屬性了;

相關文章
相關標籤/搜索