有两种防止重复提交:禁用提交按钮发出请求令牌/ ID:禁用提交按钮我们可以在函数调用HTTP请求之前禁用提交按钮,并在完成HTTP响应后再次启用它。该技术对于需要很长时间才能完成的过程(超过5秒)是有效的。由于不耐烦而无法获得结果,用户无法再次单击n’。此外,我们可能会显示一个正在Loading装载进度,以获得良好的体验。<!DOCTYPE html><html lang=“en”><head> <script type=“text/javascript” src=“https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script></head><body> <form name=“form-payment” id=“form-payment”> … </form> <script type=“text/javascript”> $(’#form-payment’).submit(function (e) { e.preventDefault(); $.ajax({ type: ‘POST’, dataType : “json”, contentType: “application/json; charset=utf-8”, url: “#”, data: “{}”, beforeSend: function(){ $(’#button-submit’).attr(‘disabled’, ‘disable’); }, complete: function(){ $(’#button-submit’).removeAttr(‘disabled’); }, success: function (data) { // do your success action }, error: function () { // do your error handler } }); }); </script></body>在beforeSend 和complete段,我添加“ disable”属性作为开关, (jquery中有专门语句防止二次提交)重点来了:Spring Boot中如何发出请求令牌/ ID这种技术实际上更复杂,更难实现,但是由于一个好的框架(如Spring Boot)使这更容易。在我们开始代码实现之前,让我们先讨论一下这个机制;加载表单页面时,发出新的requestId在调用后端服务之前将已发出的requestId发送到HTTP头后端服务标识requestId是否已注册如果requestId已经注册,那么我们可以将其标记为违规请求我们来开始代码。这里是我的JavaScript中的示例代码,用于发出新的requestId。 $(document).ready(function () { var requestId = new Date().getTime(); // <— issue new requestId every time page laoded $(’#form-payment’).submit(function (e) { e.preventDefault(); $.ajax({ type: ‘POST’, dataType : “json”, contentType: “application/json; charset=utf-8”, headers: { “requestId” : requestId }, // <— add requestId in header url: “#”, data: “{}”, beforeSend: function(){ $(’#button-submit’).attr(‘disabled’, ‘disable’); }, complete: function(){ $(’#button-submit’).removeAttr(‘disabled’); }, success: function (data) { }, error: function () { } }); }); });这里是我的Spring Boot项目中的示例代码,我创建了一个Interceptor来处理requestId:import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.ArrayList;import java.util.List;@Configurationpublic class Interceptor implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new ViolationInterceptor()).addPathPatterns(”/**"); } public class ViolationInterceptor extends HandlerInterceptorAdapter { private List<String> requestIds = new ArrayList<>(); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestId = request.getHeader(“requestId”); if (requestIds.contains(requestId)) throw new IllegalArgumentException(“Violation Request; Reason requestId already registered”); requestIds.add(requestId); return super.preHandle(request, response, handler); } }}Exception处理:import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;@ControllerAdvicepublic class ExceptionAdvisor { @ExceptionHandler(IllegalArgumentException.class) ResponseEntity illegalArgumentExceptionHandler(IllegalArgumentException e){ return ResponseEntity.ok(e.getMessage()); }}在此示例中,我使用应用程序内存来存储requestId。对于认真的开发,我建议使用内存数据库,例如Redis。实际上,我们可以在识别requestId时修改如何发布新令牌和逻辑。因为这个过程非常简单,我们需要一些东西(requestId)来识别已经请求过的东西。写在最后:既然看到这里了,觉得笔者写的还不错的就点个赞,加个关注呗!点关注,不迷路,持续更新!!!