SpringBoot如何防止重复提交?- Adrian Adendrata

栏目: Java · 发布时间: 5年前

内容简介:有两种防止重复提交:1.禁用提交按钮  2. 发出请求令牌/ ID:我们可以在函数调用HTTP请求之前禁用提交按钮,并在完成HTTP响应后再次启用它。该技术对于需要很长时间才能完成的过程(超过5秒)是有效的。由于不耐烦而无法获得结果,用户无法再次单击n'。此外,我们可能会显示一个正在Loading装载进度,以获得良好的体验。

有两种防止重复提交:1.禁用提交按钮  2. 发出请求令牌/ 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;

@Configuration
public 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;

@ControllerAdvice
public class ExceptionAdvisor {

    @ExceptionHandler(IllegalArgumentException.class)
    ResponseEntity illegalArgumentExceptionHandler(IllegalArgumentException e){
        return ResponseEntity.ok(e.getMessage());
    }
}

在此示例中,我使用应用程序内存来​​存储requestId。对于认真的开发,我建议使用内存数据库,例如Redis。

实际上,我们可以在识别requestId时修改如何发布新令牌和逻辑。因为这个过程非常简单,我们需要一些东西(requestId)来识别已经请求过的东西。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python编程快速上手

Python编程快速上手

Albert Sweigart / 王海鹏 / 人民邮电出版社 / 2016-7-1 / 69.00元

如今,人们面临的大多数任务都可以通过编写计算机软件来完成。Python是一种解释型、面向对象、动态数据类型的高级程序设计语言。通过Python编程,我们能够解决现实生活中的很多任务。 本书是一本面向实践的Python编程实用指南。本书的目的,不仅是介绍Python语言的基础知识,而且还通过项目实践教会读者如何应用这些知识和技能。本书的首部分介绍了基本Python编程概念,第二部分介绍了一些不......一起来看看 《Python编程快速上手》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具