來吧,少年,今天還能看文章學習的,一多半都是單身貴族,看朋友圈還會被虐,不如學習,上街還會被虐,不如學習,痛并快樂著。
在讀這篇文章之前,你需要了解的?
URL:統一資源定位符,是互聯網上資源的網址
例如http://www.aspxfans.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name
1.協議部分:該URL的協議部分為“http:”,這代表網頁使用的是HTTP協議。在Internet中可以使用多種協議,如HTTP,HTTPS,FTP等等本例中使用的是HTTP協議。在"HTTP"后面的“//”為分隔符
2.域名部分:該URL的域名部分為“www.aspxfans.com”。一個URL中,也可以使用IP地址作為域名使用
3.端口部分:跟在域名后面的是端口,域名和端口之間使用“:”作為分隔符。端口不是一個URL必須的部分,如果省略端口部分,將采用默認端口
4.虛擬目錄部分:從域名后的第一個“/”開始到最后一個“/”為止,是虛擬目錄部分。虛擬目錄也不是一個URL必須的部分。本例中的虛擬目錄是“/news/”
5.文件名部分:從域名后的最后一個“/”開始到“?”為止,是文件名部分,如果沒有“?”,則是從域名后的最后一個“/”開始到“#”為止,是文件部分,如果沒有“?”和“#”,那么從域名后的最后一個“/”開始到結束,都是文件名部分。本例中的文件名是“index.asp”。文件名部分也不是一個URL必須的部分,如果省略該部分,則使用默認的文件名
6.參數部分:從“?”開始到“#”為止之間的部分為參數部分,又稱搜索部分、查詢部分。本例中的參數部分為“boardID=5&ID=24618&page=1”。參數可以允許有多個參數,參數與參數之間用“&”作為分隔符。
7.錨部分:從“#”開始到最后,都是錨部分。本例中的錨部分是“name”。錨部分也不是一個URL必須的部分
我們是如果通過瀏覽器訪問頁面的?
當我們打開瀏覽器,在瀏覽器的地址欄中輸入URL地址http://www.gacl.cn:8080/WebDemo1/1html
去訪問服務器上的1.html這個web資源的過程中,瀏覽器和服務器都做了神馬操作呢,我們是怎么在瀏覽器里面看到1.html這個web資源里面的內容的呢?
瀏覽器和服務器做了以下幾個操作:
1、瀏覽器根據主機名"www.gacl.cn"去操作系統的Hosts文件中查找主機名對應的IP地址。
2、瀏覽器如果在操作系統的Hosts文件中沒有找到對應的IP地址,就去互聯網上的DNS服務器上查找"www.gacl.cn"這臺主機對應的IP地址。
3、瀏覽器查找到"www.gacl.cn"這臺主機對應的IP地址后,就使用IP地址連接到Web服務器。
4、瀏覽器連接到web服務器后,就使用http協議向服務器發送請求,發送請求的過程中,瀏覽器會向Web服務器以Stream(流)的形式傳輸數據,告訴Web服務器要訪問服務器里面的哪個Web應用下的Web資源
5、瀏覽器做完上面4步工作后,就開始等待,等待Web服務器把自己想要訪問的1.html這個Web資源傳輸給它。
6、服務器接收到瀏覽器傳輸的數據后,開始解析接收到的數據,服務器解析"GET /WebDemo1/1.html "里面的內容時知道客戶端瀏覽器要訪問的是WebDemo1應用里面的1html這個Web資源,然后服務器就去讀取1.html這個Web資源里面的內容,將讀到的內容再以Stream(流)的形式傳輸給瀏覽器,
7、瀏覽器拿到服務器傳輸給它的數據之后,就可以把數據展現給用戶看了
相同域?
在客戶端編程語言中,同源策略是一個很重要的安全理念,它在保證數據的安全性方面有著重要的意義。同 源策略規定跨域之間的腳本是隔離的,一個域的腳本不能訪問和操作另外一個域的絕大部分屬性和方法。
當兩個域具有相同的協議,相同的域名,同端口,說明這是相同域,其中任意一個不同,都屬于跨域。
受到同源策略的影響,跨域資源共享就會受到制約。但是隨著人們的實踐和瀏覽器的進步,目前在跨域請求的技巧上,有很多寶貴經驗的沉淀和積累。這里我把跨域資源共享分成兩種,一種是單向的數據請求,還有一種是雙向的消息通信。接下來羅列出常見的一些跨域方式.
單項跨域
JSONP
JSONP (JSON with Padding)是一個簡單高效的跨域方式,HTML中的script標簽可以加載并執行其他域的javascript,于是我們可以通過script標記來動態加載其他域的資源。
在js中,我們直接用XMLHttpRequest請求不同域上的數據時,是不可以的,但是,眾所周知,script的標簽有一個src屬性,指向一個地址,加載成功之后就可以成功調用里面的文件。那么,我們可以以這種形式,進行跨域訪問。jsonp正是利用這個特性來實現的。
舉個栗子
//script可以跨域
//需要跨域的時候可以創建一個script標簽
var jsonp = document.createElement("script");
//指定類型
jsonp.type = "text/javascript";
//添加鏈接地址
jsonp.src = "http://10.0.154.249/text.js?callback=jsonpCallback";
//將這個拼接 好的script標簽添加到head標簽中。
document.getElementsByTagName("head")[0].appendChild(jsonp);
//回調函數
function jsonpCallback(ret){
alert(ret)
}
在異地服務器中,有一個text.js文件,我們只要把需要傳輸的數據,以參數的形式,傳遞到我們的回調函數中就可以了。
異地服務中text.js文件內容
jsonpCallback("飯飯愛分享");
運行結果
當然上栗也可以直接寫一個script標簽或者向筆者這樣動態創建script標簽。
這樣jsonp的原理就很清楚了,通過script標簽引入一個js文件,這個js文件載入成功后會執行我們在url參數中指定的函數,并且會把我們需要的json數據作為參數傳入。所以jsonp是需要服務器端的頁面進行相應的配合的。
如果你的頁面使用jquery,那么通過它封裝的方法就能很方便的來進行jsonp操作了。
<script>
$.getJSON(''http://10.0.154.249/text.js?callback=?",function(ret ){
alert(ret)
})
</script>
原理是一樣的,只不過我們不需要手動的插入script標簽以及定義回掉函數。jquery會自動生成一個全局函數來替換callback=?中的問號,之后獲取到數據后又會自動銷毀,實際上就是起一個臨時代理函數的作用。$.getJSON方法會自動判斷是否跨域,不跨域的話,就調用普通的ajax方法;跨域的話,則會以異步加載js文件的形式來調用jsonp的回調函數。
JSONP易于實現,但是也會存在一些安全隱患,如果第三方的腳本隨意地執行,那么它就可以篡改頁面內容,截獲敏感數據。但是在受信任的雙方傳遞數據,JSONP是非常合適的選擇。
window.name
window對象有個name屬性,該屬性有個特征:即在一個窗口(window)的生命周期內,窗口載入的所有的頁面都是共享一個window.name的,每個頁面對window.name都有讀寫的權限,window.name是持久存在一個窗口載入過的所有頁面中。當然,如果有需要,其中的任何一個頁面都可以對window.name的值進行修改。的,并不會因新頁面的載入而進行重置。
注意,window.name的值只能是字符串的形式,這個字符串的大小最大能允許2M左右甚至更大的一個容量,具體取決于不同的瀏覽器,但一般是夠用了。
舉個栗子
比如有一個www.example.com/a.html
頁面,需要通過a.html頁面里的js來獲取另一個位于不同域上的頁面www.cnblogs.com/data.html
里的數據。
data.html頁面里的代碼很簡單,就是給當前的window.name設置一個a.html頁面想要得到的數據值。data.html里的代碼:
那么在a.html頁面中,我們怎么把data.html頁面載入進來呢?顯然我們不能直接在a.html頁面中通過改變window.location來載入data.html頁面,因為我們想要即使a.html頁面不跳轉也能得到data.html里的數據。答案就是在a.html頁面中使用一個隱藏的iframe來充當一個中間人角色,由iframe去獲取data.html的數據,然后a.html再去得到iframe獲取到的數據。
充當中間人的iframe想要獲取到data.html的通過window.name設置的數據,只需要把這個iframe的src設為www.cnblogs.com/data.html
就行了。然后a.html想要得到iframe所獲取到的數據,也就是想要得到iframe的window.name的值,還必須把這個iframe的src設成跟a.html頁面同一個域才行,不然根據前面講的同源策略,a.html是不能訪問到iframe里的window.name屬性的。這就是整個跨域過程。
看下a.html頁面的代碼:
上面的代碼只是最簡單的原理演示代碼,你可以對使用js封裝上面的過程,比如動態的創建iframe,動態的注冊各種事件等等,當然為了安全,獲取完數據后,還可以銷毀作為代理的iframe。
雙向跨域
document.domain
瀏覽器都有一個同源策略,其限制之一就是第一種方法中我們說的不能通過ajax的方法去請求不同源中的文檔。 它的第二個限制是瀏覽器中不同域的框架之間是不能進行js的交互操作的。有一點需要說明,不同的框架之間(父子或同輩),是能夠獲取到彼此的window對象的,但是你卻不能使用獲取到的window對象的屬性和方法(html5中的postMessage方法是一個例外),
比如有一個頁[http://www.example.com/a.html](http://www.example.com/a.html)
,這個頁面里面有一個iframe,它的src是http://example.com/b.html
很顯然,這個頁面與它里面的iframe框架是不同域的,所以我們是無法通過在頁面中書寫js代碼來獲取iframe中的東西的。
但是我們可以使用document.domain,我們只要把http://example.com/a.html
和http://example.com/b.html
這兩個頁面的document.domain都設成相同的域名就可以了。但要注意的是,document.domain的設置是有限制的,我們只能把document.domain設置成自身或更高一級的父域,且主域必須相同。例如:a.b.example.com 中某個文檔的document.domain 可以設成a.b.example.com、b.example.com 、example.com中的任意一個,但是不可以設成 c.a.b.example.com,因為這是當前域的子域,也不可以設成baidu.com,因為主域已經不相同了。
在http://example.com/a.html
中設置document.domain
在頁面
http://example.com/b.html
中也設置document.domain,而且這也是必須的,雖然這個文檔的domain就是example.com,但是還是必須顯示的設置document.domain的值.這樣我們就可以通過js訪問到iframe中的各種屬性和對象了。
不過如果你想在
http://www.example.com/a.html
頁面中通過ajax直接請求http://example.com/b.html
頁面,即使你設置了相同的document.domain也還是不行的,所以修改document.domain的方法只適用于不同子域的框架間的交互。
如果你想通過ajax的方法去與不同子域的頁面交互,除了使用jsonp的方法外,還可以用一個隱藏的iframe來做一個代理。原理就是讓這個iframe載入一個與你想要通過ajax獲取數據的目標頁面處在相同的域的頁面,所以這個iframe中的頁面是可以正常使用ajax去獲取你要的數據的,然后就是通過我們剛剛講得修改document.domain的方法,讓我們能通過js完全控制這個iframe,這樣我們就可以讓iframe去發送ajax請求,然后收到的數據我們也可以獲得了。
window.postMessage
window.postMessage(message,targetOrigin) 方法是html5新引進的特性,可以使用它來向其它的window對象發送消息,無論這個window對象是屬于同源或不同源,目前IE8+、FireFox、Chrome、Opera等瀏覽器都已經支持window.postMessage方法。
調用postMessage方法的window對象是指要接收消息的那一個window對象,該方法的第一個參數message為要發送的消息,類型只能為字符串;第二個參數targetOrigin用來限定接收消息的那個window對象所在的域,如果不想限定域,可以使用通配符 * 。
需要接收消息的window對象,可是通過監聽自身的message事件來獲取傳過來的消息,消息內容儲存在該事件對象的data屬性中。
上面所說的向其他window對象發送消息,其實就是指一個頁面有幾個框架的那種情況,因為每一個框架都有一個window對象。在討論第二種方法的時候,我們說過,不同域的框架間是可以獲取到對方的window對象的,而且也可以使用window.postMessage這個方法。下面看一個簡單的示例,有兩個頁面
我們運行a頁面后得到的結果:
我們看到b頁面成功的收到了消息。
使用postMessage來跨域傳送數據還是比較直觀和方便的,但是缺點是IE6、IE7不支持,所以用不用還得根據實際需要來決定。
本文參考1:http://web.jobbole.com/88525/
本文參考2:http://www.educity.cn/wenda/53094.html