在前端開發中遇到高并發場景時,若不加控制容易出現重復請求,這可能導致接口壓力增加、數據異常、用戶體驗變差等問題。以下是前端防止/解決重復請求的常見方法,按不同場景歸類總結:
🌟 一、常見重復請求場景
-
用戶頻繁點擊按鈕:多次觸發相同請求(例如提交表單、下載操作)。
-
路由短時間內多次跳轉或刷新:導致重復加載數據。
-
多次調用 debounce/throttle 未正確控制函數執行時機。
-
輪詢或 WebSocket 消息導致并發訪問同一接口。
🚀 二、常用解決方案
? 1. 禁用按鈕防止多次點擊
const [loading, setLoading] = useState(false);const handleClick = async () => {if (loading) return;setLoading(true);try {await fetchData();} finally {setLoading(false);}
};
<Button loading={loading} onClick={handleClick}>提交</Button>
? 2. 使用請求緩存 + Map 記錄請求狀態
原理:在請求發出前先檢查是否已有相同請求在進行。
const requestCache = new Map();const requestWithDeduplication = (url: string, options: any = {}) => {if (requestCache.has(url)) {return requestCache.get(url); // 復用已有請求}const req = fetch(url, options).finally(() => {requestCache.delete(url); // 請求結束后清除緩存});requestCache.set(url, req);return req;
};
適合統一封裝
fetch
、axios
請求,避免相同參數的并發請求。
? 3. 使用 Axios 的 CancelToken 取消上一次請求
let controller: AbortController | null = null;const request = async (url: string) => {if (controller) {controller.abort(); // 取消上一個請求}controller = new AbortController();try {const res = await fetch(url, { signal: controller.signal });return await res.json();} catch (e) {if (e.name === 'AbortError') {console.log('Request canceled');}}
};
適合搜索聯想、快速切換 tab 等需要 只保留最后一次請求 的場景。
? 4. 使用 debounce/throttle 防抖節流
import { debounce } from 'lodash';const fetchData = debounce((params) => {// 實際請求
}, 300);<input onChange={(e) => fetchData(e.target.value)} />
控制高頻輸入類請求頻率,減少并發請求量。
? 5. 后端冪等 + 前端唯一請求 ID(可選高級方案)
-
給每次請求生成唯一 ID(如 UUID),發送給后端。
-
后端對相同 ID 請求只處理一次。
-
前端避免再做復雜狀態判斷,適合交易、支付類場景。
🧠 小結對照表
場景 | 推薦方案 |
---|---|
按鈕多次點擊 | 禁用按鈕 / loading 狀態 |
相同請求并發 | 請求緩存 Map / Axios CancelToken |
輸入頻繁調用接口 | debounce 防抖 |
只保留最后一個請求 | AbortController / CancelToken |
表單提交 /交易請求冪等 | 請求唯一 ID + 后端冪等處理 |
如果你告訴我你遇到的具體是哪個頁面或場景(例如點擊下載、搜索聯想、多 tab 切換等),我可以給出更加定制化的解決方案。