js中各種跨域問題實戰小結(一)


什么是跨域?為什么要實現跨域呢?

這是因為JavaScript出於安全方面的考慮,不允許跨域調用其他頁面的對象。也就是說只能訪問同一個域中的資源。我覺得這就有必要了解下javascript中的同源策略是怎么回事了:javascript的同源策略 。這里更加細致詳細的總結了為什么要跨域:javascript跨域之  什么是跨域?為什么跨域?

於是當我們想某些特定的功能的時候,實現合理的跨域請求就顯得比較重要了。我努力通過自己動手,自己模擬環境來切實的嘗試跨域是怎么回事。

第一部分總結如下:

 

-->1.原生Ajax對象xhr的跨域

-->2.簡單jsonp

-->3.圖像Ping

-->4.document.domain+iframe實現跨域

 

javascript中的原生Ajax對象XMLHTTPRequest

先看原生ajax的實現代碼:

 1       var xhr = createXHR();//for IE封裝一下瀏覽器不同的ajax對象
 2       xhr.onload = function(event){ //確保接收到適當的響應
 3         if((xhr.status >=200&&xhr.status<300)||xhr.status == 304){
 4           alert(xhr.responseText);
 5         }else{
 6           alert('error:'+xhr.status);
 7         }
 8       }
 9       xhr.open('get','**.php',true);//open方法的參數open(get/post,url,是否發送異步請求)
10       xhr.send(null);//open只是啟動一個請求,並未發送,調用send()才會發送請求

我們知道想上面這樣就可以發送ajax請求啦,得到的響應數據會自動填充xhr對象的屬性,我們就可以去訪問啦。

但是,就是有上面說到的限制,只能想同一個域中使用相同端口和協議的URL發送請求。然后就是解決跨域的問題了。

好在有個東西叫CORS(跨源資源共享),它背后的思想就是使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功還是失敗。

實現方法:

1.發送get/post請求時,給它添加一個額外的Origin頭部,其中包含請求頁面的源信息(協議,域名和端口),以便服務器根據這個頭部信息來決定是否響應,像這樣的:  

Origin:http://www.nczonline.net

2.如果服務器認為這個請求可以接受,就在頭部發回相同的源信息:

Access-Control-Allow-Origin:http://www.nczonline.net

如果沒有這個頭部或者源信息不匹配,那么服務器就會駁回請求,正常的情況下瀏覽器會處理請求。

深入研究CORS:HTTP access control (CORS)

另外,說到HTTP頭部相關,我覺得也有必要了解下通常的Request Headers和Response Headers通常都有哪些參數,它們會告訴我們很多信息的:

之所以想到了解,是因為記得看過這篇文章,小胡子利用了響應頭部的Date來實現了個倒計時:利用XMLHttpRequest響應頭的Date實現倒計時

懂PHP的同學也可以嘗試下這個:javascript跨域(三)CROS 

 

 

JSONP(雙向)

     1、什么是JSONP:

          jsonp(json with padding),jsonp與json看起來差不多,只不過jsonp是被包含在函數調用中的json。jsonp由兩部分組成,一部分是回調函數,一部分是數據。回調函數就是當響應到來時應該在頁面中調用的函數,數據就是傳入回調函數中的json數據。他的優點是:第一,他能直接訪問響應文本;第二,jsonp支持在瀏覽器與服務器之間的雙向通信。但同時也存在缺點:它無法保證加載的來自其他域的代碼是安全的,還有就是無法判斷jsonp的請求是否失敗。 

     2、使用方法:

   動態創建<script>節點:

1 function handleResponse(response){
2          alert("你的ip地址:"+response.ip+",ip地址所在的城市:"+response.city+",所在省份:"+response.region_name);
3 
4       }
5 
6       var script = document.createElement('script');
7       script.src = 'http://freegeoip.net/json/?callback=handleResponse';/*http://freegeoip.net是一個jsonp地理定位服務*/ 
8 document.body.insertBefore(script,document.body.firstChild);

但是如何判斷script節點加載完畢是個問題:ie只能通過script的readystatechange屬性,其他瀏覽器支持script的load事件。

如果用了jquery的話,就不用寫上面那些代碼了,jquery做了很多工作,調用$.ajax()方法的時候,如果想使用jsonp這種方法,封裝參數即可了。

移步這里查看詳細:jQuery中的$.ajax()方法使用jsonp

同樣,這也有個PHP實踐:javascript跨域(二)JSONP

 

圖像ping(單向)

    1、什么是圖像ping:

        圖像ping是與服務器進行簡單、單向的跨域通信的一種方式,請求的數據是通過查詢字符串的形式發送的,而相應可以是任意內容,但通常是像素圖或204相應(No Content)。 圖像ping有兩個主要缺點:首先就是只能發送get請求,其次就是無法訪問服務器的響應文本。

   2、使用方法:

1       var img = new Image();
2       img.onload = img.onerror = function(){
3          alert("done!");
4       };
5       img.src = "https://raw.githubusercontent.com/zhangmengxue/Todo-List/master/me.jpg";
6       document.body.insertBefore(img,document.body.firstChild);

然后頁面上就可以顯示我放在我的github上某個地方的照片啦。

與<img>類似的可以跨域內嵌資源的還有:

(1)<script src=""></script>標簽嵌入跨域腳本。語法錯誤信息只能在同源腳本中捕捉到。上面jsonp也用到了呢。

(2) <link src="">標簽嵌入CSS。由於CSS的松散的語法規則,CSS的跨域需要一個設置正確的Content-Type消息頭。不同瀏覽器有不同的限制: IEFirefoxChromeSafari (跳至CVE-2010-0051)部分 和 Opera

(3)<video> 和 <audio>嵌入多媒體資源。

(4)<object>, <embed> 和 <applet>的插件。

(5)@font-face引入的字體。一些瀏覽器允許跨域字體( cross-origin fonts),一些需要同源字體(same-origin fonts)。

(6) <frame> 和 <iframe>載入的任何資源。站點可以使用X-Frame-Options消息頭來阻止這種形式的跨域交互。

 

 

document.domain+iframe實現跨域

首先要知道,只是在頁面上通過<iframe>載入了資源,是不能與他交互的,像我的博客右邊的那個About中的那個Github的Fllow一樣的,只能去訪問。那我們想要實現交互的話,對於主域相同而子域不同的情景,就可以借助於document.domain來實現。

www.one.com上的a.html:

 1       document.domain = 'a.com';
 2       var ifr = document.createElement('iframe');
 3       ifr.src = 'http://script.a.com/b.html';
 4       ifr.style.display = 'none';
 5       document.body.appendChild(ifr);
 6       ifr.onload = function(){
 7           var doc = ifr.contentDocument || ifr.contentWindow.document;
 8           // 在這里操縱b.html
 9           alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
10       };

w3w.one.com上的b.html:

document.domain = 'a.com';

這種方式就可以實現a頁面和b頁面交互了。適用於{www.kuqin.com, kuqin.com, script.kuqin.com, css.kuqin.com}這樣的域名下的頁面間,這里默認他們使用相同的協議和端口。

 備注:某一頁面的domain默認等於window.location.hostname。主域名是不帶www的域名,例如a.com,主域名前面帶前綴的通常都為二級域名或多級域名,例如www.a.com其實是二級域名。 domain只能設置為主域名,不可以在b.a.com中將domain設置為c.a.com。

同時在修改document.domain的時候也需要注意一些問題,和可能產生的影響:修改document.domain可能產生的影響

這部分參考了這里:js中跨域問題總結document.domain+iframe部分

 

這里說到了document.domain,那么我也就想到了document的其他屬性,放這一起看下:

(1)document.referrer  簡單來說,一般情況下瀏覽器請求A時發送的Header中Referer是什么,那么拿到A頁面后document.referre的值就是什么.我們可以通過訪問document的這個屬性來知道我們的頁面是從哪里來的。通常還能看到一些參數。

(2)document.links  它能得到頁面中所有<a>和<area>標簽中的href屬性值。

(3)document.compatMode 如果得到的值是CSS1Compat那么是標准模式,BackCompat則是混雜模式

(4)document.readyState 文檔加載屬性 值為complete即加載完全 loading則正在加載。

上面只舉例列了一些,其實還有很多很好用的,可以自行查閱手冊:document的屬性和方法

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

 

后面第二部分待總結的有:

-->5.利用iframe和location.hash

-->6.window.name跨域實現

-->7.HTML5 postMessage實現跨域

下一篇:  js中各種跨域問題實戰小結(二)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM