- 講解順序:
- AJAX 的概念及由來
- JS 和 jQuery 中的 ajax
- 瀏覽器機制
- AJAX 跨域
AJAX 的概念
- 在講解 AJAX 的概念之前,我先提一個問題。
這是一個典型的 B/S 模式。
-
PS. B/S結構(Browser/Server,瀏覽器/伺服器模式),是WEB興起後的一種網路結構模式,WEB瀏覽器是客戶端最主要的應用軟體。這種模式統一了客戶端,將系統功能實現的核心部分集中到伺服器上,簡化了系統的開發、維護和使用。客戶機上只要安裝一個瀏覽器
-
B/S 模式
- 優點:一個伺服器可以響應多個客戶端
- 缺點:短連結(與 C/S 相反)
- 特點:客戶端主動去請求(request),伺服器端被迫去響應(response)
這一點很重要
- 好處:大大減少了伺服器的資源
- 結論:伺服器永遠沒辦法主動告訴客戶端一些資訊
在這張圖中,左側是選單,很早之前的做法是點選重新整理按鈕會對整個頁面進行重新整理,這樣做的弊端是什麼?如何不使用 AJAX 進行區域性重新整理?
- 弊端
- I/O 網路吞吐量過大
- 網頁載入慢
- 耗記憶體及 CPU
- 區域性重新整理
- 很 low,但是隻有唯一的方法:iframe
- 雖然是區域性重新整理,但是是區域性整體重新整理
那麼有什麼辦法能進行資料實時推送(例如股票價格)?
於是誕生了這幾個方法。
- 輪詢機制(依舊很佔伺服器資源,low)
- 伺服器推送(提一下,想了解的下次,不是這次要講的東西)
那麼,iframe 最大的缺點是什麼?
- 外面的 window 和 iframe 的 window 不是一個物件,也就是說,不在一個 DOM 樹中!這樣的話,外面內容和裡面內容互動起來特別繁瑣。
- AJAX 解決了這個問題。
瞭解 AJAX 之前先要了解一下前後端的互動過程。
大家慢慢看……
JS 和 jQuery 中的 ajax
- AJAX 全稱:即“Asynchronous JavaScript And XML” (代表一種格式,比如:json、HTML、XML、text、jsonp等等)
- AJAX 的核心物件是 XMLHttpRequest 物件
- 檢視方法(就是 network 裡的 XHR)
- IE7及其他瀏覽器:XMLHttpRequest
- IE6及以下:ActiveXObject
// 簡單的ajax請求
var xhr = new XMLHttpRequest();// 建立
xhr.onreadystatechange = function() {// onreadystatechange 不是檢測方法,而是狀態改變後更新的狀態
if (xhr.status == 200) {
/*
普及一下常用的狀態碼
200:ok,伺服器成功返回資料
400:Bad Request,語法錯誤
401:請求需要認證
404:not found,找不到頁面
500:伺服器遇到意外錯誤
503:伺服器正在維護或者過載無法完成請求
其他百度去
*/
if (xhr.readyState == 4) {
/*
xhr.readyState 是 ajax 狀態
普及一下這個4是什麼意思:
0:建立服務
1:開啟服務
2:傳送服務
3:伺服器響應
4:載入成功
*/
var data = JSON.parse(xhr.responseText);// responseText 是返回的文字或物件
}
} else {
// 如果不是正常返回
console.log("資料返回失敗!狀態碼" + xhr.status + "狀態資訊:" + xhr.statusText)
// xhr.statusText是瀏覽器的錯誤資訊,因為跨瀏覽器的時候,可能不太一致,不建議直接使用它
}
}
xhr.open("post", "list.json?rand="+new Date(), true);// 開啟,最後一個 bool 代表是否非同步,這一步僅僅只配置了 ajax 的基本資訊,而並沒有對伺服器請求
// rand=new Date()是為了讓每一次請求 url 都不同,用來區分快取
xhr.setRequestHeader("Content-Type","application/www-x-form-urlencoded");
xhr.send(null);// 向伺服器傳送請求
複製程式碼
jQuery 的 ajax 實際上就是封裝了上面的程式碼
$.ajax({
type:"get",
dataType: "json",
url: url,
async: true,
success: function(){},
error: function(){}
})
下面用 chrome 和 Firefox 來演示跨域問題。
複製程式碼
瀏覽器機制
- 用 原生 AJAX 進行跨域請求,會發現報錯了,仔細分析錯誤
- 得到結論:AJAX 本身是可以跨域的,但是瀏覽器的同源策略機制,限制了 XMLHttpRequest 請求,導致無法跨域,所以 AJAX 在瀏覽器中跨域是一個偽命題,而 AJAX 不是無法跨域的主謀。
- 以下幾種情況會被瀏覽器視為不安全,而直接進行攔截
- 同源規則:同域名、埠、協議(只針對 XMLHttpRequest)
- www.a.com 和 a.com實際是配置的兩個域名
編號 | url | 說明 | 是否允許通訊 |
---|---|---|---|
1 | http://www.a.com/a.js http://www.a.com/b.js |
同一域名下 | 允許 |
2 | http://www.a.com/a/a.js http://www.a.com/b/b.js |
同一域名不同資料夾 | 允許 |
3 | http://www.a.com:8080/a.js http://www.a.com:9090/a.js |
同一域名不同埠號 | 不允許 |
4 | http://www.a.com/a.js https://www.a.com/b.js |
同一域名不同協議 | 不允許 |
5 | http://www.a.com/a.js http://192.168.4.158/b.js |
域名與域名對應的ip地址 | 不允許 |
6 | http://www.a.com/a.js http://github.a.com/b.js |
主域名相同,子域名不同 | 不允許 |
7 | http://www.a.com/a.js http://a.com/b.js |
同一域名,不同二級域名(同上) | 不允許(cookie這種情況下也不允許訪問) |
8 | http://www.a.com/a.js http://www.b.com/b.js |
不同域名 | 不允許 |
AJAX 跨域
- 代理
- 向伺服器傳送對應的 url,伺服器在後臺做了一個代理,前端只需要訪問A的伺服器也就相當與訪問了B的伺服器,比如在A(
www.a.com/sever.php
)和B(www.b.com/sever.php
)各有一個伺服器,A的後端(www.a.com/sever.php
)直接訪問B的服務,然後把獲取的響應值返回給前端。這種代理屬於後臺的技術,所以不展開敘述。
- 向伺服器傳送對應的 url,伺服器在後臺做了一個代理,前端只需要訪問A的伺服器也就相當與訪問了B的伺服器,比如在A(
- JSONP
- 說白了就是利用同源策略的漏洞,利用建立標籤的形式進行載入。
- JS 中的實現
//建立一個script元素
var Scr = document.reateElement('script');
//宣告型別
Scr.type='text/javascript';
//新增src屬性,引入跨域訪問的url
Scr.src=url;
//在頁面中新增新建立的script元素
document.getElementsByTagName('body')[0].appendChild(Scr)
複製程式碼
- jQuery 中的實現:
$.ajax({
url: 'http://192.168.1.114/yii/demos/test.js', //不同的域
type: 'GET', // jsonp模式只有GET是合法的
data: {
'action': 'aaron'
}, // 預傳參的陣列
dataType: 'jsonp', // 資料型別
jsonp: 'backfunc', // 指定回撥函式名,與伺服器端接收的一致,並回傳回來
})
複製程式碼
整個流程就是:
客戶端傳送一個請求,規定一個可執行的函式名(這裡就是jQuery做了封裝的處理,自動幫你生成回撥函式並把資料取出來供success屬性方法來呼叫,不是傳遞的一個回撥控制程式碼),服務端接受了這個backfunc函式名,然後把資料通過實參的形式傳送出去
其實就是jquery內部會轉化成http://192.168.1.114/yii/demos/test.js?backfunc=jQuery2030038573939353227615_1402643146875&action=aaron
然後動態載入
<script type="text/javascript" src="http://192.168.1.114/yii/demos/test.js?backfunc=jQuery2030038573939353227615_1402643146875&action=aaron"></script>
- XHR2
-
“XHR2” 全稱 “XMLHttpRequest Level2” 是HTML5提供的方法,對跨域訪問提供了很好的支援,並且還有一些新的功能。
-
IE10以下的版本都不支援
-
只需要在伺服器端頭部加上下面兩句程式碼:
-
header( "Access-Control-Allow-Origin:*" );
-
header( "Access-Control-Allow-Methods:POST,GET" );
-