🎬 HoRain云小助手:个人主页
🔥 个人专栏: 《Linux 系列教程》《c语言教程》
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
专栏介绍
专栏名称 | 专栏介绍 |
本专栏主要撰写C干货内容和编程技巧,让大家从底层了解C,把更多的知识由抽象到简单通俗易懂。 | |
本专栏主要是注重从底层来给大家一步步剖析网络协议的奥秘,一起解密网络协议在运行中协议的基本运行机制! | |
全面深入解析 docker 容器,从基础到进阶,涵盖原理、操作、实践案例,助您精通 docker。 | |
本专栏主要撰写Linux干货内容,从基础到进阶,知识由抽象到简单通俗易懂,帮你从新手小白到扫地僧。 | |
本专栏着重撰写Python相关的干货内容与编程技巧,助力大家从底层去认识Python,将更多复杂的知识由抽象转化为简单易懂的内容。 | |
本专栏主要是发布一些考试和练习题库(涵盖软考、HCIE、HRCE、CCNA等) |
目录
一、前端防重复提交
1. 禁用按钮 + 状态锁定
- 实现逻辑:在请求发起时禁用按钮,直到收到响应或超时。
- 代码示例:
const submitButton = document.getElementById('submit-btn'); async function handleSubmit() { submitButton.disabled = true; // 锁定按钮 try { const response = await fetch('/api/order', { method: 'POST', body: JSON.stringify({ orderId: '123' }) }); // 处理响应... } catch (error) { console.error('提交失败:', error); } finally { submitButton.disabled = false; // 解锁按钮 } }
2. 防抖(Debounce)机制
- 适用场景:防止用户快速多次点击触发重复请求。
- 代码示例(使用 Lodash):
import { debounce } from 'lodash'; const debouncedSubmit = debounce(async (data) => { await fetch('/api/submit', { method: 'POST', body: data }); }, 1000); // 1秒内多次调用只执行一次 // 在点击事件中调用 button.addEventListener('click', () => debouncedSubmit(formData));
二、生成唯一请求标识(Request ID)
1. 客户端生成唯一 ID
- 实现逻辑:每次请求携带唯一标识(如 UUID),服务端根据该 ID 去重。
- 代码示例:
import { v4 as uuidv4 } from 'uuid'; // 生成唯一请求 ID const requestId = uuidv4(); // 发送请求时附加到 Header 或 Body fetch('/api/payment', { method: 'POST', headers: { 'X-Request-ID': requestId }, body: JSON.stringify({ amount: 100 }) });
2. 结合本地存储暂存已发送 ID
- 实现逻辑:将已发送的请求 ID 暂存到内存或
localStorage
,避免页面刷新后重复。const sentRequests = new Set(); function sendRequest(data) { const requestId = uuidv4(); if (sentRequests.has(requestId)) return; sentRequests.add(requestId); fetch('/api/submit', { method: 'POST', body: JSON.stringify({ ...data, requestId }) }).finally(() => sentRequests.delete(requestId)); }
三、幂等性令牌(Idempotency Key)
1. 获取服务端令牌
- 流程:
- 客户端先请求一个临时令牌(如
/api/get-token
)。 - 提交 POST 请求时携带该令牌。
- 服务端校验令牌有效性后处理请求,并标记令牌为已使用。
- 客户端先请求一个临时令牌(如
- 代码示例:
// 1. 获取令牌 const { token } = await fetch('/api/get-token').then(res => res.json()); // 2. 提交请求时附加令牌 fetch('/api/create-order', { method: 'POST', headers: { 'Idempotency-Key': token }, body: JSON.stringify({ productId: '789' }) });
2. 自动重试时复用令牌
- 场景:网络失败后重试请求时,使用相同的令牌。
let idempotencyKey = localStorage.getItem('last_key') || uuidv4(); function retryRequest() { fetch('/api/retry', { method: 'POST', headers: { 'Idempotency-Key': idempotencyKey }, body: data }).then(() => { localStorage.removeItem('last_key'); }).catch(() => { localStorage.setItem('last_key', idempotencyKey); }); }
四、状态管理 + 请求追踪
1. 使用全局状态标记请求状态
- 实现逻辑:通过 Redux、Vuex 或 React Context 跟踪请求状态。
- 示例(React + Context):
const { isSubmitting, setSubmitting } = useRequestContext(); const handleSubmit = async () => { if (isSubmitting) return; // 阻止重复提交 setSubmitting(true); await fetch('/api/submit', { method: 'POST' }); setSubmitting(false); };
2. 请求队列(Request Queue)
- 场景:严格保证请求顺序,避免并发冲突。
const requestQueue = []; let isProcessing = false; function enqueueRequest(request) { requestQueue.push(request); if (!isProcessing) processQueue(); } async function processQueue() { isProcessing = true; while (requestQueue.length > 0) { const request = requestQueue.shift(); await fetch(request.url, request.options); } isProcessing = false; }
五、客户端缓存响应结果
- 逻辑:对相同参数的请求,直接返回缓存结果。
- 代码示例:
const responseCache = new Map(); async function cachedPost(url, data) { const key = JSON.stringify({ url, data }); if (responseCache.has(key)) { return responseCache.get(key); } const response = await fetch(url, { method: 'POST', body: JSON.stringify(data) }); const result = await response.json(); responseCache.set(key, result); return result; }
六、与服务端协作的兜底方案
尽管客户端可减少重复提交,但最终幂等性需服务端保障:
- 服务端去重:通过唯一索引、请求 ID 或令牌实现。
- 幂等性接口设计:如使用
PUT
替代POST
更新资源。
总结:客户端幂等性方案对比
方案 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
禁用按钮 + 状态锁定 | 用户触发的重复提交 | 简单易实现 | 无法防止网络自动重试 |
唯一请求 ID | 需严格去重的关键操作(如支付) | 强一致性 | 需服务端支持 |
幂等性令牌 | 高安全要求的业务 | 服务端可控,安全性高 | 增加一次令牌获取请求 |
请求队列 | 需顺序执行的批量操作 | 保证顺序 | 实现复杂度高 |
建议根据业务场景选择组合方案(如 防重复提交按钮 + 唯一请求 ID),并确保服务端实现幂等性逻辑。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙