2005年,Jesse James Garrett撰寫了一篇文章《Ajax - A New Approach to Web Applications》,這篇文章中描繪了一個被稱為Ajax(Asynchronous JavaScript+XML,即異步JavaScript+XML)的技術。這個技術涉及發送伺服器請求額外資料而不刷新頁面,從而實現更好地用戶體驗。 Garrett解釋了這個技術如何改變自Web誕生以來就一直延續的傳統點擊等待的模式。
把Ajax推到歷史舞台上的關鍵技術是XMLHttpRequest(XHR)物件。在XHR出現之前,Ajax風格的通訊必須透過一些黑科技來實現,主要是使用隱藏的窗格或內嵌窗格。 XHR為發送伺服器請求和取得相應提供了合理的介面。這個介面可以實現異步從伺服器獲取額外數據,意味著用戶不用頁面刷新也可以獲得數據。透過XHR物件取得資料後,可以使用DOM方法把資料插入網頁。
XHR物件的API普遍認為比較難用,而Fetch API自動誕生以後迅速成為了XHR更現代的替代標準,Fetch API支援期約promise和服務線程(service worker),已經成為及其強大的Web開發工具。
透過XHR進行Ajax通訊的一個主要限制是跨源安全策略。預設情況下,XHR只能存取與發起請求的頁面在相同網域內的資源。這個安全限制可以防止某些惡意行為。不過,瀏覽器也需要支援合法跨來源存取的能力。
跨來源資源共享(CORS,Cross-Origin Rerource Sharing)定義了瀏覽器與伺服器如何實現跨來源通訊。 CORS背後的基本想法就是使用自訂的HTTP頭部允許瀏覽器和伺服器相互了解,以確定請求或相應應該成功還是失敗。
對於簡單的請求,例如GET或POST請求,沒有自訂頭部,而且請求體是text/plain類型,這樣的請求在發送時會有一個額外的頭部叫Origin。 Origin頭部包含發送請求的頁面的來源(協定、網域名稱、連接埠),以便伺服器確定是否為其提供回應。
現代瀏覽器透過XMLHttpRequst物件原生支援CORS,在嘗試存取不同來源的資源時,這個行為會被自動觸發。要向不同網域的來源傳送請求,可以使用標準XHR物件並給open()方法傳入一個絕對URL,例如:
let xhr = new XMLHttpRequest();xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.reaponseText); }else{ alert("Request was unsuccessful:"+xhr.status); } }};xhr.open("get","http://www.nezha.con/page/",true);xhr.send(null);
跨域XHR物件允許存取status和statusText屬性,也允許同步請求,出於安全考慮,跨域XHR物件也施加了一些額外的限制。
不能使用setRequestHeader()設定自訂頭部;
不能發送和接收cookie;
getAllResponseHeaders()方法始終返回空字串;
因為無論同域還是跨域請求都是用同一個接口,所以最好在訪問本地資源時使用相對URL,在存取遠端資源時使用絕對URL,這樣可以更明確地區分使用場景,同時避免在存取本地資源時出現頭部或cookie資訊存取受限的問題。
CORS通過一種叫預檢請求的伺服器驗證機制,允許使用自訂頭部、除GET和POST之外的方法,以及不同請求體內容類型。在要傳送涉及上述某種進階選項的請求時,會先想伺服器發送一個預檢請求。這個請求使用OPTIONS方法發送並包含以下頭部:
Origin:與簡單請求相同;
Access-Control-Request-Method:請求希望使用的方法;
Access-Control-Request-Headers:(可選)要使用的逗號分隔的自訂頭部清單;
Fetch API能夠執行XMLHttpRequest物件的所有任務,但更容易使用,介面也更現代化,能夠在Web工作執行緒等Web工具中使用。 XMLHttpRequest可以選擇非同步,而Fetch API則必須是非同步。
fetch()方法是暴露在全域作用域中的,包括主頁面執行緒、模組和工作執行緒。呼叫這個方法,瀏覽器就會向給定URL發送請求。
1、分派請求
fetch()只有一個必需的參數input。多數情況下,這個參數是取得資源的URL,這個方法傳回一個期約:
let r = fetch('/bar');console.log(r);//Promise<pending>
URL的格式(相對路徑、絕對路徑等)的解釋與XHR物件相同。
當請求完成、資源可用時,期約會解決一個Response對象,這個對像是API的封裝,可以透過它取得對應資源。取得資源要使用這個物件的屬性和方法,掌握回應的情況並將負載平衡轉為有用的形式。
2.讀取回應讀取回應內容最簡單的方式是取得純文字格式的內容,只要用到text()方法。這個方法傳回一個期約,會解決為取得資源的完整內容。
3.處理狀態碼和請求失敗
Fetch API 支援透過Response的status和statusText屬性檢查回應狀態。成功獲取回應的請求通常會產生值為200的狀態碼。
4.常見Fetch請求模式
發送JSON資料
在請求體中發送參數
發送檔案
載入Blob檔案
發送跨網域請求
中斷請求
套接字websocket的目標是透過一個長時連線實現與伺服器全雙工、雙向的通信。在JavaScript中建立websocket時,一個HTTP請求會傳送到伺服器以初始化連線。伺服器回應後,連線使用HTTP中的Upgrade頭部從HTTP協定切換到websocket協定,這表示websocket不能透過標準HTTP伺服器實現,而必須使用支援該協定的專有伺服器。
因為websocket使用了自訂協議,所以URL方案稍有變化,不能再使用http://或https://,而要使用ws://和wss://。前者是不安全的連接,後者是安全連接。在執行websocket URL時,必須包含URL方案,因為將來有可能再支援其他方案。
使用自訂協定而非HTTP協定的好處是,客戶端與伺服器質檢可以發送非常少的數據,不會對HTTP造成任何負擔。使用較小的資料包讓websocket非常適合寬頻和延遲問題比較明顯的行動應用。使用自訂協定的缺點是,定義協定的時間比定義JavaScript API的時間要長,websocket得到了所有主流瀏覽器的支援。