【axios】XHR的ajax封裝+axios攔截器呼叫+請求取消
文章目錄
Http
1. 前後臺互動的基本過程
1. 前後應用從瀏覽器端向伺服器傳送HTTP請求(請求報文)
2. 後臺伺服器接收到請求後, 排程伺服器應用處理請求, 向瀏覽器端返回HTTP響應(響應報文)
3. 瀏覽器端接收到響應, 解析顯示響應體/呼叫監視回撥
2. HTTP請求報文
1. 請求行: 請求方式/url
method url
GET /product_detail?id=2
POST /login
2. 多個請求頭: 一個請求頭由name:value組成, 如Host/Cookie/Content-Type頭
Host: www.baidu.com
Cookie: BAIDUID=AD3B0FA706E; BIDUPSID=AD3B0FA706;
Content-Type: application/x-www-form-urlencoded 或者 application/json
3. 請求體
username=tom&pwd=123
{"username": "tom", "pwd": 123}
3. HTTP響應報文
1. 響應行: 響應狀態碼/對應的文字
2. 多個響應頭: 如 Content-Type / Set-Cookie 頭
Content-Type: text/html;charset=utf-8
Set-Cookie: BD_CK_SAM=1;path=/
3. 響應體
html文字/json文字/js/css/圖片...
4. post請求體文字引數格式
1. Content-Type: application/x-www-form-urlencoded;charset=utf-8
用於鍵值對引數,引數的鍵值用=連線, 引數之間用&連線
例如: name=%E5%B0%8F%E6%98%8E&age=12
2. Content-Type: application/json;charset=utf-8
用於json字串引數
例如: {"name": "%E5%B0%8F%E6%98%8E", "age": 12}
3. Content-Type: multipart/form-data
用於檔案上傳請求
5. 常見響應狀態碼
200 OK 請求成功。一般用於GET與POST請求
201 Created 已建立。成功請求並建立了新的資源
401 Unauthorized 未授權/請求要求使用者的身份認證
404 Not Found 伺服器無法根據客戶端的請求找到資源
500 Internal Server Error 伺服器內部錯誤,無法完成請求
6. 不同型別的請求及其作用:
1. GET: 從伺服器端讀取資料
2. POST: 向伺服器端新增新資料
3. PUT: 更新伺服器端已經資料
4. DELETE: 刪除伺服器端資料
7. API的分類
1. REST API: restful
傳送請求進行CRUD哪個操作由請求方式來決定
同一個請求路徑可以進行多個操作
請求方式會用到GET/POST/PUT/DELETE
2. 非REST API: restless
請求方式不決定請求的CRUD操作
一個請求路徑只對應一個操作
一般只有GET/POST
測試: 可以使用json-server快速搭建模擬的rest api 介面
XHR
1. 理解
使用XMLHttpRequest (XHR)物件可以與伺服器互動, 也就是傳送ajax請求
前端可以獲取到資料,而無需讓整個的頁面重新整理。
這使得Web頁面可以只更新頁面的區域性,而不影響使用者的操作。
2. 區別一般的HTTP請求與ajax請求
ajax請求是一種特別的http請求
對伺服器端來說, 沒有任何區別, 區別在瀏覽器端
瀏覽器端發請求: 只有XHR或fetch發出的才是ajax請求, 其它所有的都是非ajax請求
瀏覽器端接收到響應
一般請求: 瀏覽器一般會直接顯示響應體資料, 也就是我們常說的重新整理/跳轉頁面
ajax請求: 瀏覽器不會對介面進行任何更新操作, 只是呼叫監視的回撥函式並傳入響應相關資料
3. 使用語法
XMLHttpRequest(): 建立XHR物件的建構函式
status: 響應狀態碼值, 比如200, 404
statusText: 響應狀態文字
readyState: 標識請求狀態的只讀屬性
0: 初始
1: open()之後
2: send()之後
3: 請求中
4: 請求完成
onreadystatechange: 繫結readyState改變的監聽
responseType: 指定響應資料型別, 如果是'json', 得到響應後自動解析響應體資料
response: 響應體資料, 型別取決於responseType的指定
timeout: 指定請求超時時間, 預設為0代表沒有限制
ontimeout: 繫結超時的監聽
onerror: 繫結請求網路錯誤的監聽
open(): 初始化一個請求, 引數為: (method, url[, async])
send(data): 傳送請求
abort(): 中斷請求
getResponseHeader(name): 獲取指定名稱的響應頭值
getAllResponseHeaders(): 獲取所有響應頭組成的字串
setRequestHeader(name, value): 設定請求頭
4.XHR的簡單封裝
/*
1.函式的返回值為promise, 成功的結果為response, 失敗的結果為error
2.能處理多種型別的請求: GET/POST/PUT/DELETE
3.函式的引數為一個配置物件
{
url: '', // 請求地址
method: '', // 請求方式GET/POST/PUT/DELETE
params: {}, // GET/DELETE請求的query引數
data: {}, // POST或DELETE請求的請求體引數
}
4.響應json資料自動解析為js的物件/陣列
*/
function axios({url, params={}, data={}, method='GET'}) {
// 返回一個promise物件
return new Promise((resolve, reject) => {
// 建立一個XHR物件
const xhr = new XMLHttpRequest()
// 根據params拼接query引數(拼接到url上) id=1&xxx=abc
/*
{
id: 1,
xxx: 'abc'
}
*/
let queryStr = Object.keys(params).reduce((pre, key) => {
pre += `&${key}=${params[key]}`
return pre
}, '')
if (queryStr.length>0) {
queryStr = queryStr.substring(1)
url += '?' + queryStr
}
/*另一種拼接
let queryString = ''
Object.keys(params).forEach(key => {
queryString += `${key}=${params[key]}&`
})
if (queryString) { // id=1&xxx=abc&
// 去除最後的&
queryString = queryString.substring(0, queryString.length-1) //有返回
// 接到url
url += '?' + queryString
}
*/
// 請求方式轉換為大寫
method = method.toUpperCase()
// 初始化一個非同步請求(還沒發請求)
xhr.open(method, url, true)
// 繫結請求狀態改變的監聽
xhr.onreadystatechange = function () {
// 如果狀態值不為4, 直接結束(請求還沒有結束)
if (xhr.readyState !== 4) {
return
}
// 如果響應碼在200~~299之間, 說明請求都是成功的
if (xhr.status>=200 && xhr.status<300) {
// 準備響應資料物件
const responseData = {
data: xhr.response,
status: xhr.status,
statusText: xhr.statusText
}
// 指定promise成功及結果值
resolve(responseData)
} else { // 請求失敗了
// 指定promise失敗及結果值
const error = new Error('request error staus '+ xhr.status)
reject(error)
}
}
// 指定響應資料格式為json ==> 內部就是自動解析好
//不再單獨需要對響應的json字串轉換為json物件 JSON.parse(xhr.response)
xhr.responseType = 'json'
// 如果是post/put請求
if (method==='POST' || method==='PUT') {
// 設定請求頭: 使請求體引數以json形式傳遞
xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8')
// 傳送json格式請求體引數,得轉換為json字串
const dataJson = JSON.stringify(data)
// 傳送請求, 指定請求體資料
xhr.send(dataJson)
} else {// GET/DELETE請求
// 傳送請求
xhr.send(null)
}
})
}
axios
1. axios的特點
基本promise的非同步ajax請求庫
瀏覽器端/node端都可以使用
支援請求/響應攔截器
支援請求取消
請求/響應資料轉換
批量傳送多個請求
PS:JQuery發ajax請求必須得先指定回撥,但axios不用
2. axios常用語法
axios(config): 通用/最本質的發任意型別請求的方式
axios(url[, config]): 可以只指定url發get請求
axios.request(config): 等同於axios(config)
axios.get(url[, config]): 發get請求
axios.delete(url[, config]): 發delete請求
axios.post(url[, data, config]): 發post請求
axios.put(url[, data, config]): 發put請求
axios.defaults.xxx: 請求的預設全域性配置
axios.interceptors.request.use(): 新增請求攔截器
axios.interceptors.response.use(): 新增響應攔截器
axios.create([config]): 建立一個新的axios(它沒有下面的功能)
axios.Cancel(): 用於建立取消請求的錯誤物件
axios.CancelToken(): 用於建立取消請求的token物件
axios.isCancel(): 是否是一個取消請求的錯誤
axios.all(promises): 用於批量執行多個非同步請求
axios.spread(): 用來指定接收所有成功資料的回撥函式的方法
3. 難點語法理解與使用
1). axios.create(config) #返回的是函式物件
a. 根據指定配置建立一個新的axios, 也就就每個新axios都有自己的配置
b. 新axios只是沒有取消請求和批量發請求的方法, 其它所有語法都是一致的
c. 為什麼要設計這個語法?
需求: 專案中有部分介面需要的配置與另一部分介面需要的配置不太一樣, 如何處理
解決: 建立2個新axios, 每個都有自己特有的配置, 分別應用到不同要求的介面請求中
axios.defaults.baseURL = 'http://localhost:3000'
// 使用axios發請求
axios({
url: '/posts' // 請求3000
})
// axios({
// url: '/xxx' // 請求4000
// })
const instance = axios.create({
baseURL: 'http://localhost:4000'
})
// 使用instance發請求
// instance({
// url: '/xxx' // 請求4000
// })
instance.get('/xxx')
2). 攔截器函式/ajax請求/請求的回撥函式的呼叫順序
a. 說明: 呼叫axios()並不是立即傳送ajax請求, 而是需要經歷一個較長的流程
b. 流程: 請求攔截器2 => 請求攔截器1 => 發ajax請求 => 響應攔截器1 => 響應攔截器2 => 請求的回撥
c. 注意: 此流程是通過promise串連起來的, 請求攔截器傳遞的是config, 響應攔截器傳遞的是response
錯誤流程控制與錯誤處理
/*
requestInterceptors: [{fulfilled1(){}, rejected1(){}}, {fulfilled2(){}, rejected2(){}}]
responseInterceptors: [{fulfilled11(){}, rejected11(){}}, {fulfilled22(){}, rejected22(){}}]
chain: [
fulfilled2, rejected2, fulfilled1, rejected1,
dispatchReqeust, undefined,
fulfilled11, rejected11, fulfilled22, rejected22
]
promise鏈回撥: config
=> (fulfilled2, rejected2) => (fulfilled1, rejected1) // 請求攔截器處理
=> (dispatchReqeust, undefined) // 發請求
=> (fulfilled11, rejected11) => (fulfilled22, rejected22) // 響應攔截器處理
=> (onResolved, onRejected) // axios發請求回撥處理
*/
// 新增請求攔截器(回撥函式)
axios.interceptors.request.use(
config => {
console.log('request interceptor1 onResolved()')
return config //同promise將成功繼續傳遞 否則沒reuturn返回的promise值為undifined
},
error => {
console.log('request interceptor1 onRejected()')
return Promise.reject(error); //同promise,異常傳遞
}
)
axios.interceptors.request.use(
config => {
console.log('request interceptor2 onResolved()')
return config
},
error => {
console.log('request interceptor2 onRejected()')
return Promise.reject(error);
}
)
// 新增響應攔截器
axios.interceptors.response.use(
response => {
console.log('response interceptor1 onResolved()')
return response
},
function (error) {
console.log('response interceptor1 onRejected()')
return Promise.reject(error);
}
)
axios.interceptors.response.use(
response => {
console.log('response interceptor2 onResolved()')
return response
},
function (error) {
console.log('response interceptor2 onRejected()')
return Promise.reject(error);
}
)
axios.get('http://localhost:3000/posts')
.then(response => {
console.log('data', response.data)
})
.catch(error => {
console.log('error', error.message)
})
3). 取消請求
a. 基本流程:
配置cancelToken物件
快取用於取消請求的cancel函式
在後面特定時機呼叫cancel函式取消請求
在錯誤回撥中判斷如果error是cancel, 做相應處理
b. 實現功能
點選按鈕, 取消某個正在請求中的請求
在請求一個介面前, 取消前面一個未完成的請求
PS:取消請求成功,則進入失敗回撥,此時error是cancel物件,也有message屬性
<body>
<button onclick="getProducts1()">獲取商品列表1</button><br>
<button onclick="getProducts2()">獲取商品列表2</button><br>
<button onclick="cancelReq()">取消請求</button><br>
<script src="https://cdn.bootcss.com/axios/0.19.0/axios.js"></script>
<script>
// 新增請求攔截器
axios.interceptors.request.use((config) => {
// 在準備發請求前, 取消未完成的請求
if (typeof cancel==='function') {
cancel('取消請求')
}
// 新增一個cancelToken的配置
config.cancelToken = new axios.CancelToken((c) => { // c是用於取消當前請求的函式
// 儲存取消函式, 用於之後可能需要取消當前請求
cancel = c
})
return config
})
// 新增響應攔截器
axios.interceptors.response.use(
response => {
cancel = null
return response
},
error => {
if (axios.isCancel(error)) {// 取消請求的錯誤
// cancel = null
console.log('請求取消的錯誤', error.message) // 做相應處理
// 中斷promise連結
return new Promise(() => {})
} else { // 請求出錯了
cancel = null
// 將錯誤向下傳遞
// throw error
return Promise.reject(error)
}
}
)
let cancel // 用於儲存取消請求的函式
function getProducts1() {
axios({
url: 'http://localhost:4000/products1',
}).then(
response => {
console.log('請求1成功了', response.data)
},
error => {// 只用處理請求失敗的情況, 取消請求的錯誤的不用
console.log('請求1失敗了', error.message)
}
)
}
function getProducts2() {
axios({
url: 'http://localhost:4000/products2',
}).then(
response => {
console.log('請求2成功了', response.data)
},
error => {
console.log('請求2失敗了', error.message)
}
)
}
function cancelReq() {
// alert('取消請求')
// 執行取消請求的函式
if (typeof cancel === 'function') {
cancel('強制取消請求')
} else {
console.log('沒有可取消的請求')
}
}
</script>
</body>
相關文章
- 封裝ajax、axios請求封裝iOS
- React、Axios、MockJs實現Ajax的請求攔截ReactiOSMockJS
- 封裝axios請求封裝iOS
- axios 攔截器iOS
- axios攔截器iOS
- 非同步請求xhr、ajax、axios與fetch的區別比較非同步iOS
- axios 請求資料封裝iOS封裝
- vue中axios請求的封裝VueiOS封裝
- 學習axios必知必會(2)~axios基本使用、使用axios前必知細節、axios和例項物件區別、攔截器、取消請求iOS物件
- Axios、axios攔截器、fetch-jsonp ——0807iOSJSON
- 十. Axios網路請求封裝iOS封裝
- axios(xhr) 和 fetch 兩種請求方式iOS
- 二次封裝axios,根據引數來實現多個請求多次攔截封裝iOS
- [譯]axios 是如何封裝 HTTP 請求的iOS封裝HTTP
- axios取消請求 CancelToken(如何使用)iOS
- axios原始碼分析——取消請求iOS原始碼
- 多個ajax axios請求,呼叫按照順序執行iOS
- 基於原生fetch封裝一個帶有攔截器功能的fetch,類似axios的攔截器封裝iOS
- axios 攔截器 的使用方法iOS
- axios原始碼分析——攔截器iOS原始碼
- axios的全域性攔截之axios.interceptorsiOS
- axios攔截器原理是什麼?iOS
- 非同步請求與中斷 ( XHR,Axios,Fetch對比 )非同步iOS
- Vue功能篇 - 3.封裝axios請求庫Vue封裝iOS
- vue介面請求方式axios二次封裝VueiOS封裝
- vue axios路由跳轉取消所有請求VueiOS路由
- vue中使用axios傳送ajax請求VueiOS
- 首頁 使用axios 傳送ajax請求iOS
- axios 請求iOS
- Vuex結合Axios非同步請求資料的封裝VueiOS非同步封裝
- 基於小程式請求介面 wx.request 封裝的類 axios 請求封裝iOS
- 六九、ajax,fetch,axios,wx.request封裝iOS封裝
- React 中用jQuery的ajax 和 axios請求資料ReactjQueryiOS
- 前端快閃四: 攔截axios請求和響應前端iOS
- vue2.0 axios post請求傳參問題(ajax請求)VueiOS
- axios封裝iOS封裝
- 封裝axios封裝iOS
- Vue路由切換 & Axios介面取消重複請求Vue路由iOS