<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      Fork me on GitHub

      前端跨域請求方法匯總

      受瀏覽器同源策略的限制,本域的js不能操作其他域的頁面對象(比如DOM)。但在安全限制的同時也給注入iframe或是ajax應用上帶來了不少麻煩。所以我們要通過一些方法使本域的js能夠操作其他域的頁面對象或者使其他域的js能操作本域的頁面對象(iframe之間)。這里需要明確的一點是:所謂的域跟js的存放服務器沒有關系,比如baidu.com的頁面加載了google.com的js,那么此js的所在域是baidu.com而不是google.com。也就是說,此時該js能操作baidu.com的頁面對象,而不能操作google.com的頁面對象。

      一、單向跨域

      一般用于獲取數據。

      1、使用JSONP跨域

      原理:因為通過script標簽引入的js是不受同源策略的限制的(正如前文提到的baidu.com的頁面加載了google.com的js)。所以我們可以通過script標簽引入一個js或者是一個其他后綴形式(如php,jsp等)的文件,此文件返回一個js函數的調用,如返回JSONP_getUsers(["paco","john","lili"]),也就是說此文件返回的結果調用了JSONP_getUsers函數,并且把["paco","john","lili"]傳進去,這個["paco","john","lili"]是一個用戶列表。那么如果此時我們的頁面中有一個JSONP_getUsers函數,那么JSONP_getUsers就被調用到,并且傳入了用戶列表。此時就實現了在本域獲取其他域數據的功能,也就是跨域。

      實現例子如下:

      前端引入遠程js并定義好JSONP_getUsers函數,注意需要先定義好JSONP_getUsers函數,避免在遠程js加載完成并調用JSONP_getUsers時,此函數不存在:

      //本域為baidu.com
      <script>
          function JSONP_getUsers(users){
              console.dir(users);
          }
      </script>
      //加載google.com的getUsers.php
      <script src="http://www.google.com/getUsers.php"></script>
      

      需要google.com提供支持,getUsers.php代碼如下:

      <?php>
          echo 'JSONP_getUsers(["paco","john","lili"])';//返回一個js函數的調用
      ?>
      

      為什么script標簽引入的文件不受同源策略的限制?因為script標簽引入的文件內容是不能夠被客戶端的js獲取到的,不會影響到被引用文件的安全,所以沒必要使script標簽引入的文件遵循瀏覽器的同源策略。而通過ajax加載的文件內容是能夠被客戶端js獲取到的,所以ajax必須遵循同源策略,否則被引入文件的內容會泄漏或者存在其他風險。

      JSONP的缺點則是:它只支持GET請求而不支持POST等其它類型的HTTP請求(雖然采用post+動態生成iframe是可以達到post跨域的目的,但這樣做是一個比較極端的方式,不建議采用)。一般get請求能完成所有功能。比如如果需要給其他域服務器傳送參數可以在請求后掛參數(注意不要掛隱私數據),即

      <script src="http://www.google.com/getUsers.php?flag=do&time=1"></script>。
      

      JSONP易于實現,但是也會存在一些安全隱患,如果第三方的腳本隨意地執行,那么它就可以篡改頁面內容,截獲敏感數據。但是在受信任的雙方傳遞數據,JSONP是非常合適的選擇。可以看出來JSONP跨域一般用于獲取其他域的數據。

      一般能夠用JSONP實現跨域就用JSONP實現,這也是前端用的最多的跨域方法。

      2、動態創建script標簽

      這種方法其實是JSONP跨域的簡化版,JSONP只是在此基礎上加入了回調函數。

      比如上例中的getUsers.php返回的如果不是一個js函數的調用,而是一個js變量,如:

      <?php>
          echo 'var users=["paco","john","lili"]';//返回一個js變量users
      ?>
      

      那么在本域下就可以取到data變量,這里需要注意判斷script節點是否加載完畢,如:

      js.onload = js.onreadystatechange = function() {
          if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {
              console.log(users);//此處取出其他域的數據
              js.onload = js.onreadystatechange = null;
          }
      };
      

      3、flash URLLoader

      flash有自己的一套安全策略,服務器可以通過crossdomain.xml文件來聲明能被哪些域的SWF文件訪問,SWF也可以通過API來確定自身能被哪些域的SWF加載。當跨域訪問資源時,例如從域baidu.com請求域google.com上的數據,我們可以借助flash來發送HTTP請求。首先,修改域google.com上的crossdomain.xml(一般存放在根目錄,如果沒有需要手動創建) ,把baidu.com加入到白名單。其次,通過Flash URLLoader發送HTTP請求,最后,通過Flash API把響應結果傳遞給JavaScript。Flash URLLoader是一種很普遍的跨域解決方案,不過需要支持iOS的話,這個方案就不可行了。

      4、CORS

      此跨域方法目前只在很少的瀏覽器中得以支持,這些瀏覽器可以發送一個跨域的HTTP請求(Firefox, Google Chrome等通過XMLHTTPRequest實現,IE8下通過XDomainRequest實現),請求的響應必須包含一個Access- Control-Allow-Origin的HTTP響應頭,該響應頭聲明了請求域的可訪問權限。例如baidu.com對google.com下的getUsers.php發送了一個跨域的HTTP請求(通過ajax),那么getUsers.php必須加入如下的響應頭:

      header("Access-Control-Allow-Origin: http://www.baidu.com");//表示允許baidu.com跨域請求本文件  
      

      5、window.name

      window 對象的name屬性是一個很特別的屬性,當該window的location變化,然后重新加載,它的name屬性可以依然保持不變。那么我們可以在頁面 A中用iframe加載其他域的頁面B,而頁面B中用JavaScript把需要傳遞的數據賦值給window.name,iframe加載完成之后(iframe.onload),頁面A修改iframe的地址,將其變成同域的一個地址,然后就可以讀出iframe的window.name的值了(因為A中的window.name和iframe中的window.name互相獨立的,所以不能直接在A中獲取window.name,而要通過iframe獲取其window.name)。這個方式非常適合單向的數據請求,而且協議簡單、安全。不會像JSONP那樣不做限制地執行外部腳本。

      6、服務器代理

      在數據提供方沒有提供對JSONP協議或者 window.name協議的支持,也沒有對其它域開放訪問權限時,我們可以通過server proxy的方式來抓取數據。例如當baidu.com域下的頁面需要請求google.com下的資源文件getUsers.php時,直接發送一個指向 google.com/getUsers.php的Ajax請求肯定是會被瀏覽器阻止。這時,我們在baidu.com下配一個代理,然后把Ajax請求綁定到這個代理路徑下,例如baidu.com/proxy/, 然后這個代理發送HTTP請求訪問google.com下的getUsers.php,跨域的HTTP請求是在服務器端進行的(服務器端沒有同源策略限制),客戶端并沒有產生跨域的Ajax請求。這個跨域方式不需要和目標資源簽訂協議,帶有侵略性。

      二、雙向跨域

      兩個iframe之間或者兩個頁面之間,一般用于獲取對方數據,document.domain方式還可以直接操作對方DOM

      7、document.domain(兩個iframe之間)

      通過修改document的domain屬性,我們可以在域和子域或者不同的子域之間通信。同域策略認為域和子域隸屬于不同的域,比如baidu.com和 youxi.baidu.com是不同的域,這時,我們無法在baidu.com下的頁面中調用youxi.baidu.com中定義的JavaScript方法。但是當我們把它們document的domain屬性都修改為baidu.com,瀏覽器就會認為它們處于同一個域下,那么我們就可以互相獲取對方數據或者操作對方DOM了。

      問題:

      • 安全性,當一個站點被攻擊后,另一個站點會引起安全漏洞。
      • 如果一個頁面中引入多個iframe,要想能夠操作所有iframe,必須都得設置相同domain。

      8、location.hash(兩個iframe之間),又稱FIM,Fragment Identitier Messaging的簡寫

      因為父窗口可以對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中,數據容量和類型都有限等。下面舉例說明:

      假如父頁面是baidu.com/a.html,iframe嵌入的頁面為google.com/b.html(此處省略了域名等url屬性),要實現此兩個頁面間的通信可以通過以下方法 

      (1) a.html傳送數據到b.html

      • a.html下修改iframe的src為google.com/b.html#paco
      • b.html監聽到url發生變化,觸發相應操作

      (2) b.html傳送數據到a.html,由于兩個頁面不在同一個域下IE、Chrome不允許修改parent.location.hash的值,所以要借助于父窗口域名下的一個代理iframe

      • b.html下創建一個隱藏的iframe,此iframe的src是baidu.com域下的,并掛上要傳送的hash數據,如src="http://www.baidu.com/proxy.html#data"
      • proxy.html監聽到url發生變化,修改a.html的url(因為a.html和proxy.html同域,所以proxy.html可修改a.html的url hash)
      • a.html監聽到url發生變化,觸發相應操作

      b.html頁面的關鍵代碼如下

      try {
          parent.location.hash = 'data';
      } catch (e) {
          // ie、chrome的安全機制無法修改parent.location.hash,
          var ifrproxy = document.createElement('iframe');
          ifrproxy.style.display = 'none';
          ifrproxy.src = "http://www.baidu.com/proxy.html#data";
          document.body.appendChild(ifrproxy);
      }
      

      proxy.html頁面的關鍵代碼如下

      //因為parent.parent(即baidu.com/a.html)和baidu.com/proxy.html屬于同一個域,所以可以改變其location.hash的值
      parent.parent.location.hash = self.location.hash.substring(1);
      

      9、使用HTML5的postMessage方法(兩個iframe之間或者兩個頁面之間)

      高級瀏覽器Internet Explorer 8+, chrome,Firefox , Opera  和 Safari 都將支持這個功能。這個功能主要包括接受信息的"message"事件和發送消息的"postMessage"方法。比如baidu.com域的A頁面通過iframe嵌入了一個google.com域的B頁面,可以通過以下方法實現A和B的通信。

      A頁面通過postMessage方法發送消息:

      window.onload = function() {
          var ifr = document.getElementById('ifr');
          var targetOrigin = "http://www.google.com";
          ifr.contentWindow.postMessage('hello world!', targetOrigin);
      };
      

      postMessage的使用方法:

      otherWindow.postMessage(message, targetOrigin);

      otherWindow:   指目標窗口,也就是給哪個window發消息,是 window.frames 屬性的成員或者由 window.open 方法創建的窗口

      message:   是要發送的消息,類型為 String、Object (IE8、9 不支持)

      targetOrigin:   是限定消息接收范圍,不限制請使用 '*'

       

      B頁面通過message事件監聽并接受消息:

      var onmessage = function (event) {
        var data = event.data;//消息
        var origin = event.origin;//消息來源地址
        var source = event.source;//源Window對象
        if(origin=="http://www.baidu.com"){
      console.log(data);//hello world!
        }
      };
      if (typeof window.addEventListener != 'undefined') {
        window.addEventListener('message', onmessage, false);
      } else if (typeof window.attachEvent != 'undefined') {
        //for ie
        window.attachEvent('onmessage', onmessage);
      }
      

      同理,也可以B頁面發送消息,然后A頁面監聽并接受消息。

      總結

      跨域的方法很多,不同的應用場景我們都可以找到一個最合適的解決方案。比如單向的數據請求,我們應該優先選擇JSONP或者window.name,雙向通信優先采取location.hash,在未與數據提供方達成通信協議的情況下我們也可以用server proxy的方式來抓取數據。

       

      原文鏈接:深入理解前端跨域方法和原理

      posted @ 2017-09-21 12:33  一像素  閱讀(1650)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产偷自一区二区三区在线| 国产午夜精品福利视频| 熟女激情乱亚洲国产一区| 西贡区| www亚洲精品| 欧美18videosex性欧美tube1080 | 国产欧美日韩高清在线不卡| 国产欧美另类久久久精品不卡| 无码国内精品久久人妻蜜桃| 东京热加勒比无码少妇| 亚洲综合一区二区三区不卡| 亚洲自拍偷拍福利小视频| 黄页网址大全免费观看| 熟女一区| 欧美三级a做爰在线观看| 精品人妻系列无码天堂| 无码人妻丰满熟妇区毛片| 国产香蕉久久精品综合网| 沧州市| 高清自拍亚洲精品二区| 日韩在线视频线观看一区| 麻豆国产AV剧情偷闻女邻居内裤| 亚洲香蕉av一区二区蜜桃| 亚洲区福利视频免费看| 成人网站av亚洲国产| 久久亚洲人成网站| 色婷婷五月综合久久| 精品综合久久久久久98| 国产精品一区二区三区黄色| 国产精品亚洲二区在线播放| 日韩av日韩av在线| 天堂网亚洲综合在线| 好男人社区神马在线观看www | 亚洲精品国产精品国在线| 人妻少妇精品无码专区| 两个人看的www免费视频中文| 国产一区二区三区在线观| 桦甸市| 中文字幕日韩有码av| 国产无人区码一区二区| 扒开双腿猛进入喷水高潮叫声|