如何防止接口重复提交?

简介: 本文讨论了前端如何防止接口重复提交的问题。主要方法包括:1) 禁用提交按钮,用户点击后立即禁用并显示加载状态,请求完成后恢复;2) 使用防抖或节流技术限制请求发送的频率;3) 生成请求标识符,后端检查已处理过的请求;4) 利用状态管理库(如Redux, Vuex)跟踪请求状态,避免重复提交;5) 接口锁定,通过变量记录请求状态,防止并发请求。这些策略可单独或组合使用,以确保请求的准确性和系统稳定性。

什么是接口重复提交?

     接口重复提交指的是在网络通信中,同一个请求被客户端多次发送到服务器端的情况。这种情况可能由于多种原因导致,例如用户在等待期间多次点击提交按钮、网络超时后客户端重新发送请求、客户端发送的请求在网络传输过程中出现重复等。

     接口重复提交可能会导致多种问题,当服务器收到重复请求时,可能会多次处理相同的数据,导致数据重复操作或者产生不一致的结果。重复提交请求会增加服务器的负载和资源消耗,特别是在高并发情况下,可能会导致服务器压力过大,影响系统的性能和稳定性。有些请求是具有副作用的,例如支付、提交订单等,重复提交可能导致用户被重复扣款或者重复生成订单,从而导致业务异常或者用户不满。

     下面我们就来看看前端有哪些防止接口重复提交的方法。

前端如何防止接口的重复提交?

     禁用提交按钮

     在用户点击提交按钮后,立即禁用该按钮,防止用户多次点击。可以在接口请求结束后重新启用按钮。代码如下所示。

<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>

image.gif

显示加载状态

在用户提交表单后,显示一个加载状态的提示,告知用户正在处理请求,避免用户重复点击提交按钮。

<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>

image.gif

设置防抖或节流

在用户点击提交按钮后,使用防抖或节流的技术延迟发送请求,确保只发送一次请求。防抖和节流是一种常见的前端性能优化技术,可以控制函数的执行频率。

// 防抖函数
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秒内只允许点击一次

image.gif

生成请求标识符

在每次请求前生成一个唯一的请求标识符(例如 UUID),并将该标识符作为请求的一部分发送到后端。后端在接收到请求后,检查该标识符是否已经处理过,如果已经处理过则不再处理。前端可以通过记录请求标识符的状态来避免重复提交。

// 生成唯一标识符
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);
  });
});

image.gif

使用状态管理库

如果前端使用了状态管理库(如 Redux、Vuex 等),可以在提交请求前检查状态,确保不会重复提交相同的请求。

import store from './store'; // 引入状态管理库
document.getElementById('submitButton').addEventListener('click', function() {
  if (store.state.isSubmitting) {
    return; // 如果正在提交,则不执行后续操作
  }
  // 设置提交状态
  store.commit('setSubmitting', true);
  // 发送请求
  fetch('/api/submit', {
    method: 'POST',
    // 请求参数
  }).then(function(response) {
    // 处理响应
    store.commit('setSubmitting', false); // 恢复非提交状态
  }).catch(function(error) {
    console.error('Error:', error);
    store.commit('setSubmitting', false); // 恢复非提交状态(如果请求失败)
  });
});

image.gif

接口锁定

在前端发送请求前,先检查是否存在正在处理的相同请求,如果存在则不发送新的请求。可以使用一个变量来记录当前正在处理的请求,以防止重复提交。

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; // 解锁接口(如果请求失败)
  });
});

image.gif

以上方法可以单独使用,也可以组合使用,以提高接口请求的可靠性和安全性。

总结

     防止接口重复提交是为了确保系统的数据一致性、避免不必要的资源浪费和提升用户体验。为了避免接口重复提交带来的问题,需要在前端和后端都进行相应的处理,例如在前端禁用提交按钮、显示加载状态,在后端实现幂等性检查等。

相关文章
|
1月前
|
NoSQL 关系型数据库 MySQL
接口防刷 && 接口幂等性问题
接口防刷 && 接口幂等性问题
38 0
|
1月前
|
小程序 前端开发 开发者
调用第三方接口微信登录接口
该文档介绍了调用微信登录接口的需求和实现思路。当用户尝试访问需要登录的页面时,若未登录则弹出微信登录选项。登录过程涉及微信小程序的wx.login()方法获取临时凭证code,并将其发送到服务器,服务器通过此code换取用户的OpenID、UnionID和session_key。依据这些信息,服务器可生成自定义登录态以识别用户身份。参考微信官方文档和登录流程图进行实现。
32 9
|
1月前
|
存储 缓存 数据库
接口幂等有哪些实现方式
接口幂等有哪些实现方式
24 0
|
1月前
|
NoSQL Java API
SpringBoot项目中防止表单重复提交的两种方法(自定义注解解决API接口幂等设计和重定向)
SpringBoot项目中防止表单重复提交的两种方法(自定义注解解决API接口幂等设计和重定向)
163 0
|
1月前
|
数据库 索引
常见保持请求幂等的方式
常见保持请求幂等的方式
24 0
|
10月前
|
缓存 NoSQL JavaScript
8 种方案解决重复提交问题,还怕没有适合你的?
8 种方案解决重复提交问题,还怕没有适合你的?
|
Web App开发 网络协议 安全
GET和POST方式请求API接口数据返回
GET和POST方式请求API接口数据返回
127 0
|
设计模式 JavaScript 数据库
表单防止重复提交的四种方式
表单防止重复提交的四种方式
207 0
|
NoSQL 安全 小程序
使用token机制实现接口幂等性校验
为需要保证幂等性的每一次请求创建一个唯一标识token, 先获取token, 并将此token存入redis, 请求接口时, 将此token放到header或者作为请求参数请求接口, 后端接口判断redis中是否存在此token: 如果存在, 正常处理业务逻辑, 并从redis中删除此token, 那么, 如果是重复请求, 由于token已被删除, 则不能通过校验, 返回请勿重复操作提示, 如果不存在, 说明参数不合法或者是重复请求, 返回提示即可。
711 0
使用token机制实现接口幂等性校验
|
缓存 弹性计算 负载均衡
11. 分布式系统接口,如何避免表单的重复提交?
11. 分布式系统接口,如何避免表单的重复提交?
190 0