全面分析前端的網路請求方式
一、前端進行網路請求的關注點
大多數情況下,在前端發起一個網路請求我們只需關注下面幾點:
- 傳入基本引數(url,請求方式)
- 請求引數、請求引數型別
- 設定請求頭
- 獲取響應的方式
- 獲取響應頭、響應狀態、響應結果
- 異常處理
- 攜帶cookie設定
- 跨域請求
二、前端進行網路請求的方式
- form表單、ifream、重新整理頁面
- Ajax- 非同步網路請求的開山鼻祖
- jQuery- 一個時代
- fetch-Ajax的替代者
- axios、request等眾多開源庫
三、關於網路請求的疑問
- Ajax的出現解決了什麼問題
- 原生Ajax如何使用
- jQuery的網路請求方式
- fetch的用法以及坑點
- 如何正確的使用fetch
- 如何選擇合適的跨域方式
帶著以上這些問題、關注點我們對幾種網路請求進行一次全面的分析。
四、Ajax的出現解決了什麼問題
在Ajax出現之前,web程式是這樣工作的:
這種互動的的缺陷是顯而易見的,任何和伺服器的互動都需要重新整理頁面,使用者體驗非常差,Ajax的出現解決了這個問題。Ajax全稱AsynchronousJavaScript+ XML(非同步JavaScript和XML)
使用Ajax,網頁應用能夠快速地將增量更新呈現在使用者介面上,而不需要過載(重新整理)整個頁面。
Ajax本身不是一種新技術,而是用來描述一種使用現有技術集合實現的一個技術方案,瀏覽器的XMLHttpRequest是實現Ajax最重要的物件(IE6以下使用ActiveXObject)。
儘管X在Ajax中代表XML, 但由於jsON的許多優勢,比如更加輕量以及作為Javascript的一部分,目前jsON的使用比XML更加普遍。
廣州vi設計http://www.maiqicn.com 辦公資源網站大全 https://www.wode007.com
五、原生Ajax的用法
這裡主要分析XMLHttpRequest物件,下面是它的一段基礎使用:
var xhr = new XMLHttpRequest();
xhr.open('post','www.xxx.com',true)
// 接收返回值
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 ){
if(xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
console.log(xhr.responseText);
}
}
}
// 處理請求引數
postData = {"name1":"value1","name2":"value2"};
postData = (function(value){
var dataString = "";
for(var key in value){
dataString += key+"="+value[key]+"&";
};
return dataString;
}(postData));
// 設定請求頭
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
// 異常處理
xhr.onerror = function() {
console.log('Network request failed')
}
// 跨域攜帶cookie
xhr.withCredentials = true;
// 發出請求
xhr.send(postData);
下面分別對XMLHttpRequest物件常用的的函式、屬性、事件進行分析。
函式
open
用於初始化一個請求,用法:
xhr.open(method, url,async);
- method:請求方式,如get、post
- url:請求的url
- async:是否為非同步請求
send
用於傳送HTTP請求,即呼叫該方法後HTTP請求才會被真正發出,用法:
xhr.send(param)
- param:http請求的引數,可以為string、Blob等型別。
abort
用於終止一個ajax請求,呼叫此方法後readyState將被設定為0,用法:
xhr.abort()
setRequestHeader
用於設定HTTP請求頭,此方法必須在open()方法和send()之間呼叫,用法:
xhr.setRequestHeader(header, value);
getResponseHeader
用於獲取http返回頭,如果在返回頭中有多個一樣的名稱,那麼返回的值就會是用逗號和空格將值分隔的字串,用法:
varheader = xhr.getResponseHeader(name);
屬性
readyState
用來標識當前XMLHttpRequest物件所處的狀態,XMLHttpRequest物件總是位於下列狀態中的一個:
值 | 狀態 | 描述 |
---|---|---|
0 | UNSENT | 代理被建立,但尚未呼叫open()方法。 |
1 | OPENED | open()方法已經被呼叫。 |
2 | HEADERS_RECEIVED | send()方法已經被呼叫,並且頭部和狀態已經可獲得。 |
3 | LOADING | 下載中;responseText屬性已經包含部分資料。 |
4 | DONE | 下載操作已完成。 |
status
表示http請求的狀態, 初始值為0。如果伺服器沒有顯式地指定狀態碼, 那麼status將被設定為預設值, 即200。
responseType
表示響應的資料型別,並允許我們手動設定,如果為空,預設為text型別,可以有下面的取值:
值 | 描述 |
---|---|
"" | 將responseType設為空字串與設定為"text"相同, 是預設型別 (實際上是DOMString)。 |
"arraybuffer" | response是一個包含二進位制資料的JavaScript ArrayBuffer。 |
"blob" | response是一個包含二進位制資料的Blob物件 。 |
"document" | response 是一個htmlDocument或XML XMLDocument,這取決於接收到的資料的 MIME 型別。 |
"json" | response是一個 JavaScript 物件。這個物件是通過將接收到的資料型別視為JSON解析得到的。 |
"text" | response是包含在DOMString物件中的文字。 |
response
返回響應的正文,返回的型別由上面的responseType決定。
withCredentials
ajax請求預設會攜帶同源請求的cookie,而跨域請求則不會攜帶cookie,設定xhr的withCredentials的屬性為true將允許攜帶跨域cookie。
事件回撥
onreadystatechange
xhr.onreadystatechange = callback;
當readyState屬性發生變化時,callback會被觸發。
onloadstart
xhr.onloadstart = callback;
在ajax請求傳送之前(readyState==1後,readyState==2前),callback會被觸發。
onprogress
xhr.onprogress = function(event){
console.log(event.loaded / event.total);
}
回撥函式可以獲取資源總大小total,已經載入的資源大小loaded,用這兩個值可以計算載入進度。
onload
xhr.onload = callback;
當一個資源及其依賴資源已完成載入時,將觸發callback,通常我們會在onload事件中處理返回值。
異常處理
onerror
xhr.onerror = callback;
當ajax資源載入失敗時會觸發callback。
ontimeout
xhr.ontimeout = callback;
當進度由於預定時間到期而終止時,會觸發callback,超時時間可使用timeout屬性進行設定。
六、jQuery對Ajax的封裝
在很長一段時間裡,人們使用jQuery提供的ajax封裝進行網路請求,包括$.ajax、$.get、$.post等,這幾個方法放到現在,我依然覺得很實用。
$.ajax({
dataType: 'json', // 設定返回值型別
contentType: 'application/json', // 設定引數型別
headers: {'Content-Type','application/json'},// 設定請求頭
xhrFields: { withCredentials: true }, // 跨域攜帶cookie
data: JSON.stringify({a: [{b:1, a:1}]}), // 傳遞引數
error:function(xhr,status){ // 錯誤處理
console.log(xhr,status);
},
success: function (data,status) { // 獲取結果
console.log(data,status);
}
})
$.ajax只接收一個引數,這個引數接收一系列配置,其自己封裝了一個jqXHR物件,有興趣可以閱讀一下jQuary-ajax 原始碼
常用配置:
url
當前頁地址。傳送請求的地址。
type
型別:String請求方式 ("POST"或"GET"), 預設為"GET"。注意:其它HTTP請求方法,如PUT和DELETE也可以使用,但僅部分瀏覽器支援。
timeout
型別:Number設定請求超時時間(毫秒)。此設定將覆蓋全域性設定。
success
型別:Function請求成功後的回撥函式。
jsonp
在一個jsonp請求中重寫回調函式的名字。這個值用來替代在"callback=?"這種GET或POST請求中URL引數裡的"callback"部分。
error型別:Function。請求失敗時呼叫此函式。
注意:原始碼裡對錯誤的判定:
isSuccess = status >=200&& status <300|| status ===304;
返回值除了這幾個狀態碼都會進error回撥。
dataType
"xml": 返回 XML 文件,可用 jQuery 處理。
"html": 返回純文字 HTML 資訊;包含的 script 標籤會在插入 dom 時執行。
"script": 返回純文字 JavaScript 程式碼。不會自動快取結果。除非設定了 "cache" 引數。注意:在遠端請求時(不在同一個域下),所有 POST 請求都將轉為 GET 請求。(因為將使用 DOM 的 script標籤來載入)
"json": 返回 JSON 資料 。
"jsonp": JSONP 格式。使用 JSONP 形式呼叫函式時,如 "myurl?callback=?" jQuery 將自動替換 ? 為正確的函式名,以執行回撥函式。
"text": 返回純文字字串
data
型別:String使用JSON.stringify轉碼
complete
型別:Function請求完成後回撥函式 (請求成功或失敗之後均呼叫)。
async
型別:Boolean預設值:true。預設設定下,所有請求均為非同步請求。如果需要傳送同步請求,請將此選項設定為false。
contentType
型別:String預設值:"application/x-www-form-urlencoded"。傳送資訊至伺服器時內容編碼型別。
鍵值對這樣組織在一般的情況下是沒有什麼問題的,這裡說的一般是,不帶巢狀型別JSON,也就是 簡單的JSON,形如這樣:
{
a: 1,
b: 2,
c: 3
}
但是在一些複雜的情況下就有問題了。 例如在Ajax中你要傳一個複雜的json對像,也就說是物件嵌陣列,陣列中包括物件,你這樣傳:application/x-www-form-urlencoded這種形式是沒有辦法將複雜的JSON組織成鍵值對形式。
{
data: {
a: [{
x: 2
}]
}
}
可以用如下方式傳遞複雜的json物件
$.ajax({
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({a: [{b:1, a:1}]})
})
七、jQuery的替代者
近年來前端MV*的發展壯大,人們越來越少的使用jQuery,我們不可能單獨為了使用jQuery的Ajax api來單獨引入他,無可避免的,我們需要尋找新的技術方案。
尤雨溪在他的文件中推薦大家用axios進行網路請求。axios基於Promise對原生的XHR進行了非常全面的封裝,使用方式也非常的優雅。另外,axios同樣提供了在node環境下的支援,可謂是網路請求的首選方案。