什么是接口重復提交?
接口重復(fu)提交指的(de)是在網絡通信中(zhong),同一個請(qing)求(qiu)被客(ke)戶端多(duo)(duo)次發(fa)送(song)到(dao)服(fu)務器端的(de)情況(kuang)。這種情況(kuang)可能由于(yu)多(duo)(duo)種原因(yin)導致(zhi),例如用戶在等待期(qi)間多(duo)(duo)次點(dian)擊提交按鈕、網絡超時后客(ke)戶端重新發(fa)送(song)請(qing)求(qiu)、客(ke)戶端發(fa)送(song)的(de)請(qing)求(qiu)在網絡傳輸過程(cheng)中(zhong)出現(xian)重復(fu)等。
防止接口重復提交的幾種方式
1. 禁用提交按鈕
在用戶點(dian)擊(ji)(ji)提(ti)交(jiao)按鈕(niu)后,立即(ji)禁用該按鈕(niu),防(fang)止用戶多次點(dian)擊(ji)(ji)。可(ke)以在接口(kou)請求結束后重新啟用按鈕(niu)。
<form id="myForm">
<!-- 表單內容 -->
<button type="submit" id="submitButton">提交</button>
</form>
<script>
document.getElementById('myForm').addEventListener('submit', function(event) {
event.preventDefault(); // 阻止默認提交行為
document.getElementById('submitButton').disabled = true; // 禁用提交按鈕
// 發送請求
fetch('/api/submit', {
method: 'POST',
// 請求參數
}).then(function(response) {
// 處理響應
document.getElementById('submitButton').disabled = false; // 啟用提交按鈕
}).catch(function(error) {
console.error('Error:', error);
document.getElementById('submitButton').disabled = false; // 啟用提交按鈕(如果請求失敗)
});
});
</script>
2. 顯示加載狀態
在(zai)用(yong)戶提(ti)交表單后(hou),顯示一(yi)個加載狀態的(de)提(ti)示,告知用(yong)戶正在(zai)處(chu)理請(qing)求,避免用(yong)戶重(zhong)復點擊(ji)提(ti)交按鈕(niu)。
<form id="myForm">
<!-- 表單內容 -->
<button type="submit" id="submitButton">提交</button>
<div id="loadingMessage" style="display: none;">正在加載...</div>
</form>
<script>
document.getElementById('myForm').addEventListener('submit', function(event) {
event.preventDefault(); // 阻止默認提交行為
document.getElementById('submitButton').disabled = true; // 禁用提交按鈕
document.getElementById('loadingMessage').style.display = 'block'; // 顯示加載狀態
// 發送請求
fetch('/api/submit', {
method: 'POST',
// 請求參數
}).then(function(response) {
// 處理響應
document.getElementById('submitButton').disabled = false; // 啟用提交按鈕
document.getElementById('loadingMessage').style.display = 'none'; // 隱藏加載狀態
}).catch(function(error) {
console.error('Error:', error);
document.getElementById('submitButton').disabled = false; // 啟用提交按鈕(如果請求失敗)
document.getElementById('loadingMessage').style.display = 'none'; // 隱藏加載狀態(如果請求失敗)
});
});
</script>
3. 設置防抖或節流
在用(yong)戶點擊(ji)提交按鈕后,使用(yong)防(fang)抖或(huo)節流的技(ji)術延(yan)遲發(fa)送請求,確保只發(fa)送一(yi)次請求。防(fang)抖和節流是(shi)一(yi)種常見(jian)的前端性能優化技(ji)術,可以控制函數(shu)的執行(xing)頻率。
// 防抖函數
function debounce(func, delay) {
let timer;
return function() {
clearTimeout(timer);
timer = setTimeout(func, delay);
};
}
document.getElementById('submitButton').addEventListener('click', debounce(function() {
// 發送請求
fetch('/api/submit', {
method: 'POST',
// 請求參數
}).then(function(response) {
// 處理響應
}).catch(function(error) {
console.error('Error:', error);
});
}, 1000)); // 1秒內只允許點擊一次
4. 生成請求標識符
在每次請(qing)求(qiu)前(qian)生(sheng)成一(yi)個唯一(yi)的請(qing)求(qiu)標識符(fu)(fu)(例如 UUID),并將該標識符(fu)(fu)作為(wei)請(qing)求(qiu)的一(yi)部分(fen)發送(song)到后端。后端在接收到請(qing)求(qiu)后,檢查(cha)該標識符(fu)(fu)是否已經處理過,如果已經處理過則不再處理。前(qian)端可(ke)以通過記錄請(qing)求(qiu)標識符(fu)(fu)的狀態來避免重復提交。
// 生成唯一標識符
function generateRequestId() {
return Math.random().toString(36).substr(2, 9);
}
let requestId;
document.getElementById('submitButton').addEventListener('click', function() {
requestId = generateRequestId(); // 生成請求標識符
// 發送請求
fetch('/api/submit', {
method: 'POST',
headers: {
'X-Request-Id': requestId // 將請求標識符添加到請求頭中
},
// 請求參數
}).then(function(response) {
// 處理響應
}).catch(function(error) {
console.error('Error:', error);
});
});
5. 接口鎖定
在(zai)前端發送請(qing)求前,先(xian)檢查是否(fou)存在(zai)正在(zai)處理的(de)相同請(qing)求,如果(guo)存在(zai)則不發送新的(de)請(qing)求。可以使用一(yi)個變量來記錄當前正在(zai)處理的(de)請(qing)求,以防止重復提交。
let isRequesting = false;
document.getElementById('submitButton').addEventListener('click', function() {
if (isRequesting) {
return; // 如果正在請求,則不執行后續操作
}
isRequesting = true; // 鎖定接口
// 發送請求
fetch('/api/submit', {
method: 'POST',
// 請求參數
}).then(function(response) {
// 處理響應
isRequesting = false; // 解鎖接口
}).catch(function(error) {
console.error('Error:', error);
isRequesting = false; // 解鎖接口(如果請求失敗)
});
});