前言
在 Web 項目的開發過程中,我們常常會遇到重複請求的場景,而如果系統不對重複的請求進行處理,是有可能導致系統出現各種問題的。比如說,如果出現重複的 POST
請求就有可能導致服務端產生兩筆相同的紀錄,也就是一種冗余。那到底重複請求是怎麼產生的呢?這邊舉個例子感覺一下:
假設頁面中有一個 button,用戶點擊之後會發出一個 Ajax 請求。如果沒有對該 button 進行控制,那當用戶快速點擊該按鈕多次,就會發出重複請求。
反正就是說確實是會出現這樣的問題的,本篇也就是要來討論怎麼去解決這種問題。接下來將會以 Axios
為例進行說明,Axios
其實是對於 Ajax
的一個封裝,對於還不清楚的人可以先去看看 Ajax 原理及手動封裝。
參考
參考 | 鏈接 |
---|---|
axios中文文档 | http://www.axios-js.com/zh-cn/docs/index.html |
axios cancelToken原理解析 | https://blog.csdn.net/yishengsama/article/details/106416869 |
正文
如何取消請求
Axios
其實在底層上是透過一個叫做 XMLHttpRequest
的東西發送 http 請求的,如果要取消請求,我們可以通過 XMLHttpRequest
提供的一個 abort()
方法。
// Ajax
let xhr = new XMLHttpRequest()
xhr.open("GET", "https://mp.csdn.net/console/article", true)
xhr.send()
setTimeout(() => xhr.abort(), 3000)
上面是 Ajax
的作法,那對於 Axios
則可以通過CancelToken
來實現。
const CancelToken = axios.CancelToken
const source = CancelToken.source()
axios.get('/user/123', {
cancelToken: source.token
})
axios.post('/user/12345', {
name: 'cclin'
}, {
cancelToken: source.token
})
source.cancel('Operation canceled!'); // 取消请求,参数是可选的
這邊稍微注意下,使用 GET
的話是把 cancelToken 屬性放在第二個參數,POST
是把 cancelToken 屬性放在第三個參數。
此外,也可以通過調用 CancelToken
構造函數來實現:
const CancelToken = axios.CancelToken
let cancel
axios.get('/user/123', {
cancelToken: new CancelToken(function executor(c) {
cancel = c
})
})
cancel() // 取消請求
現在我們知道在 Axios
怎麼用 cancelToken 取消請求了,接下來看看如何判斷重複請求。
如何判斷重複請求
其實思路很簡單,當請求方式、請求 url、請求參數都一樣時,我們就可以認為請求重複了。因此在每次發起請求時,我們就可以根據當前請求的請求方式、請求 url 地址、和請求參數構成一個唯一的 key
,同時為每個請求創建一個專屬的 CancelToken
,然後把 key
跟 CancelToken
以 key-value 的形式放到一個 Map 中。放到 Map 是因為這樣可以很方便的判斷是否存在重複的請求。
import qs from 'qs'
const CancelToken = axios.CancelToken
const pendingRequest = new Map()
// GET -> params
// POST -> data
const key = [
method, url,
method === 'GET' ? qs.