精华内容
下载资源
问答
  • 主要给大家介绍了关于前端防止用户重复提交js实现的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起看看吧
  • 防止表单重复提交有很多种方法,其不外乎,客户端脚本防止刷新,服务端token验证等等,thinkphp内置了表单token验证,可以方便的防止表单重复提交
  • javascript方式防止表单重复提交
  • 防止表单重复提交

    千次阅读 2019-06-26 11:56:20
    防止表单重复提交

    嘿,大家好,今天我来介绍几种简单的防止表单重复提交的方法:

    防止表单重复提交

    方法一:前端方式

    当点击提交或者保存按钮之后,将按钮置为灰色或者不可点击状态,当Ajax回调之后,将按钮恢复

    1.点击保存,进入保存的方法中,加上下面这个,将按钮置为不可点击状态

    $("input.submitbutton").val("正在保存请稍后。。。。。。")
    $("input.submitbutton").attr("disabled","disabled");
    

    2.当保存的Ajax回调成功恢复按钮状态,或者不需要直接刷新页面就好

    $("input.submitbutton").removeAttr("disabled");
    $("input.submitbutton").val("保存");
    

    缺点:当用户通过刷新页面方式,或使用postman等工具绕过前段页面仍能重复提交表单。因此不推荐此方法。

    方法二:后端方式

    给数据库中需要的字段增加唯一键约束(简单粗暴),然后在后端捕获异常,通过try…catch的方式返回异常信息

    1.修改数据库,给需要的字段增加唯一约束(注:如果此时数据库中存在该字段的重复数据,则sql会执行不成功,需要你删除重复数据后执行sql)

    alter table 表名 add unique(字段名);
    

    2.在后端insert保存数据的位置,使用try…catch…代码块,捕获DuplicateKeyException异常,在catch中直接返回

    @RequestMapping(value = "/saveUserPojo", method = {RequestMethod.GET})
    @ResponseBody
    public Object saveUserPojo() {
        Map<String, Object> resultMap = new HashMap<String, Object>();
    
        UserPojo userPojo = new UserPojo("1", "程序猿辉辉", 23);
        try {
            repeatedSubmitService.insert(userPojo);
        } catch (DuplicateKeyException e) {
            resultMap.put("code", "400");
            resultMap.put("message", "请勿重复提交!!!");
        }
    
        resultMap.put("code", "200");
        resultMap.put("message", "保存成功");
    
        return resultMap;
    }
    

    3.在ajax回调函数用输出message(请勿重复提交!!!)

    像上面的的两种方法是比较简单的方式,可以结合起来使用。另外防止表单重复提交的方式还有好多,比如利用Session防止表单重复提交,使用AOP自定义切入实现方式表单重复提交等等比较高端一点的方式,有兴趣的小伙伴可以尝试一下,有空我也在好好研究一下,大家共同学习进步,嘿嘿!


    未完待续。。。


    今天的更新到这里就结束了,拜拜!!!

    感谢一路支持我的人,您的关注是我坚持更新的动力,有问题可以在下面评论留言或随时与我联系。。。。。。
    QQ:850434439
    微信:w850434439
    EMAIL:gathub@qq.com

    如果有兴趣和本博客交换友链的话,请按照下面的格式在评论区进行评论,我会尽快添加上你的链接。

    网站名称:GatHub-HongHui’S Blog
    网站地址:https://www.gathub.cn/
    网站描述:不习惯的事越来越多,但我仍在前进…就算步伐很小,我也在一步一步的前进。
    网站Logo/头像:头像地址

    展开全文
  • PHP防止表单重复提交

    2018-09-15 19:09:30
    日常开发中,表单的提交是无法避免的,而我们必须熟知的一点是“在做后退或刷新操作时,post会重新提交请求是有害的,而get虽然会...那么,如何防止表单重复提交呢? 其实很简单,根据数据流向的过程,可以从三个...

    日常开发中,表单的提交是无法避免的,而我们必须熟知的一点是“在做后退或刷新操作时,post会重新提交请求是有害的,而get虽然会重新获取数据但却是无害的”。所以我们要禁止用户重复提交表单。

    首先,我们要知道在什么情况下表单会重复提交

    1. 点击提交按钮两次。
    2. 点击刷新按钮。
    3. 回退,然后重复操作。
    4. 进行一些恶意操作。

    那么,如何防止表单重复提交呢?

    其实很简单,根据数据流向的过程,可以从三个层面进行控制:

    1、前端层面

    用户点击按钮触发submit时,前端js控制提交按钮的状态,将按钮的disabled属性为true,防止重复点击。

    //监听submit事件,触发后将提交按钮设置为不可用
    $('form').submit(function() {
        $('button[type=submit]').attr('disabled', true);
    });

    基本上禁用按钮后,前端不用管了,因为数据如果通不过laravel的验证或发生异常,在laravel中的做法是back()->withInput()->withErrors();这时页面会刷新,按钮会自行恢复状态。

    如果是ajax方式提交,直接在function里发送ajax请求前禁用就行了,然后根据请求的结果来恢复按钮的状态或跳转页面就可以了。

    2、服务端层面

    思路::

    在显示表单页面时,服务端生成一个随机字符串并以该字符串为key保存在session中并将其回显在表单一个隐藏的input中,当提交表单时,服务端根据这个隐藏input的值(即session中的key)去session中取值,如果该key存在于session中表示正常提交,并立即从session中删除该key,若发生重复提交,session中的这个key已经被删除了,就可以给前端相应的提示“表单重复提交”。

    缺点:

    1. 刷新界面,会导session中存放了多个key,数据冗余且存在漏洞,因为存在多个key即意味着同一时间可以使用不同key来提交同一份数据;

      【补充】laravel中可以通过flash方法来存储只在下个请求有效的session数据,即在下一请求之后,该数据会被自动从session中清除,这样确实能解决刷新界面后session中保存多个key的问题,但会带来一个新的问题,列举一个场景加以说明:假如某用户正在写评论,写到一半被旁边推荐的一篇文章吸引,就先去看文章了,等看完回来继续写完评论提交,会发生什么事?会被当做表单重复提交处理,因为查看文章时,已经将flash方式保存的session清空了。

    2. 不够简洁,要知道这里解决的问题是要防止表单重复提交,完全没有必要生成一个动态的类似token东西,针对某一类表单提交(如注册)将存储在session中的key固定就好了,这样就可以省去form中那个隐藏的input了。

    优化后的思路:

    针对不同类型的表单(这里定义登陆、注册为不同类型的表单)服务端维护多个不同的key(比如登陆表单在session中对应的key固定为‘login’,注册表单的key固定为’register’),在显示表单页面时将key保存进session(对应的value可以存1,也可以存当前时间,存当前时间的话,你可以根据在提交表彰时根据时间间隔来作进一步的控制),表单提交时将其删除,若出现重复提交,session中不存在这个key,你就可以提示用户“不要重复提交”了。

    具体实现:

    1、在controller中显示注册界面的方法里保存session

    public function showRegistrationForm(Request $request)
    {       
         $request->session()->put('register',time());
         return view('auth.register');
    }

    2、在处理表单提交方法中判断是否重复提交

    public function register(Request $request)
    {
        if($this->request->session()->has(‘register’)){
            //存在则表示是首次提交,清空session中的'register'
            $this->request->session()->forget(‘register’);
        }else{
            //否则抛http异常,跳转到403页面
            throw  new HttpException(403,'请忽重复注册');
        }
    
        //省略下面的验证、注册逻辑等代码
    }

    【补充】如果是参数验证失败,比如手机号已注册之类的,你back()->withInput()->withErrors();是会重新执行showRegistrationForm()方法的,所以出错后再次提交是不会被当做重复提交处理的

    简单对其进行封装

    <?php
    namespace App\Http\Controllers;
    
    use Illuminate\Foundation\Bus\DispatchesJobs;
    use Illuminate\Routing\Controller as BaseController;
    use Illuminate\Foundation\Validation\ValidatesRequests;
    use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
    use Illuminate\Http\Request;
    
    /**
     * 基础控制器,封装了web及api请求的一些公共方法
     * @author 94505
     *
     */
    class Controller extends BaseController
    {
        use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
    
        /**
         * 请求
         *
         * @var Request
         */
        protected $request;
    
        public function __construct()
        {
            $this->request = app('request');
        }
        /**
         * 防止表单重复提交的key前缀
         * @var string
         */
        private $formResubmitPrefix = 'f_';
    
        /**
         * 将key加个前缀
         * @param unknown $key
         * @return string
         */
        private function formResubmitKeyProcess($key){
            if(empty($key)){
                //默认使用当前路由的uri为key
                return $this->formResubmitPrefix.Route::current()->uri;
            }else{
                return $this->formResubmitPrefix.$key;
            }
        }
        /**
         * 在初始化表单前调用(如上面分步实现中的showRegistrationForm()方法中)
         * @param unknown $key
         */
        protected function formInit($key = null){
            $key = $this->formResubmitKeyProcess($key);
            $this->request->session()->put($key,time());
        }
        /**
         * 在处理表单提交的方法中调用(如上面分步实现中的register()方法)
         * @param string $message
         * @param unknown $key
         * @throws HttpException
         */
        protected function formSubmited(string $message = '请忽重复提交!',$key = null){
            $key = $this->formResubmitKeyProcess($key);
            if($this->request->session()->has($key)){
                $this->request->session()->forget($key);
            }else{
               throw  new HttpException(403,$message);
            }
        }        
        /**
         * 在处理表单提交的方法中调用(如上面分步实现中的register()方 法),该方法方便自定义重复提交时的提示页面,可以在子类中if判断一下,如果发生重复提交,响应自定义的界面
         * @param string $message
         * @param unknown $key
         */
        protected function formSubmitIsRepetition(string $message = '请勿重复提交!',$key = null){
            $key = $this->formResubmitKeyProcess($key);
            if($this->request->session()->has($key)){
                $this->request->session()->forget($key);
                return false;
            }else{
                return response()->view('errors.403',['message'=>$message],403);
            }
        }
       /**
         * 该方法用于ajax请求,返回的数据是数组
         * @param string $message
         * @param unknown $key
         */
        protected function formSubmitedForAjax(string $message = '请勿重复提交!',$key = null){
            $key = $this->formResubmitKeyProcess($key);
            if($this->request->session()->has($key)){
                $this->request->session()->forget($key);
                return false;
            }else{
                return ['result'=>'fail','message'=>$message];
            }
        }
    }
    

    在需要防止表单重复提交的控制器内,继承上面封装的Controller就可以直接调用里面的方法了,记得在子类构造方法中调用parent::__construct();,不然$this->request会为null,当然你也可以改成用全局Session辅助函数session()。

    3、数据库层面

    数据库加unique索引的话只能根据实际情况权衡决定。

    比如用户表的手机号(列phone)可用来登陆,必须要求唯一,但在大多数情况下你无法加这个索引,因为现在一般都支持多种登陆方式,如微信登陆、微博登陆,这个手机号可能会没有值,除非程序自动生成一个,但是否有必要?再比如一个varchar类型的列,虽然数据是唯一的,也不会出现空的情况,考虑到varchar类型插入与修改数据时更新索引的性能消耗,可能会放弃加这个索引。

     

    作为一个严谨的程序员,防止表单重复提交处理是必须的!

     

    展开全文
  • 在网上查看了很多关于springmvc防止表单重复提交的例子,将其中的3个整合在一起,才算是一个完整的例子。因项目中暂时还没有这么个需求,特备注下来,以防以后用到时还要大量的漫无目的的去寻找例子。实现原理为...

          在网上查看了很多关于springmvc防止表单重复提交的例子,将其中的3个整合在一起,才算是一个完整的例子。因项目中暂时还没有这么个需求,特备注下来,以防以后用到时还要大量的漫无目的的去寻找例子。

    实现原理为SpringMvc拦截器+注解的方式实现防止重复提交

    实现机制是使用token(随机码),简单说下:

    (a)进入下单页,会生成一个token,同时存在两个地方:session(或redis也可以)和页面

    (b)提交时,服务器接收到页面的token后,会和session中的token比较,相同则允许提交,同时删除session中的token;

    (c)如果重复提交,则session中已经没有token(已被步骤b删除),那么校验不通过,则不会真正提交.

    先创建一个注解:

    package com.dinfo.interceptor;

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Token {

        boolean save() default false;
        boolean remove() default false;

    }

    拦截器接口:

    package com.dinfo.interceptor;

    import java.lang.reflect.Method;
    import java.util.UUID;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.apache.log4j.Logger;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;


    public class TokenInterceptor extends HandlerInterceptorAdapter {
        private static final Logger LOG = Logger.getLogger(Token.class);
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            if (handler instanceof HandlerMethod) {
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                Method method = handlerMethod.getMethod();
                Token annotation = method.getAnnotation(Token.class);
                if (annotation != null) {
                    boolean needSaveSession = annotation.save();
                    if (needSaveSession) {
                        request.getSession(true).setAttribute("token", UUID.randomUUID().toString());
                    }
                    boolean needRemoveSession = annotation.remove();
                    if (needRemoveSession) {
                        if (isRepeatSubmit(request)) {
                             LOG.warn("please don't repeat submit,url:"+ request.getServletPath());
                            return false;
                        }
                        request.getSession(true).removeAttribute("token");
                    }
                }
                return true;
            } else {
                return super.preHandle(request, response, handler);
            }
        }

        private boolean isRepeatSubmit(HttpServletRequest request) {
            String serverToken = (String) request.getSession(true).getAttribute("token");
            if (serverToken == null) {
                return true;
            }
            String clinetToken = request.getParameter("token");
            if (clinetToken == null) {
                return true;
            }
            if (!serverToken.equals(clinetToken)) {
                return true;
            }
            return false;
        }

    }

    配置文件如下:

    <!-- 拦截器配置 -->
    <mvc:interceptors>
            <!-- 配置Token拦截器,防止用户重复提交数据 -->
            <mvc:interceptor>
                <mvc:mapping path="/**"/><!--这个地方时你要拦截得路径 我这个意思是拦截所有得URL-->
                <bean class="com.dinfo.interceptor.TokenInterceptor"/><!--class文件路径改成你自己写得拦截器路径!! -->
            </mvc:interceptor>

    </mvc:interceptors>

    页面表单中需要添加如下:<input type="hidden" name="token" value="${token}" />

    在需要生成token(通常是要点击提交得那个页面)得Controller中使用我们刚才自定义好得注解,贴代码:

    @SuppressWarnings({ "unchecked", "finally", "rawtypes" })
        @RequestMapping("/SaveDataController/show")
        @Token(save=true)
        public String saveData(HttpServletRequest request,HttpServletResponse response,String task_id){
            
            Map map = new HashMap();
            System.out.println(task_id);
            try {
                map = saveDataService.queryByTaskId(task_id);
            } catch (Exception e) {
                e.printStackTrace();
                map.put("task_id", task_id);
                map.put("savetype", "");
                map.put("memoryCodes", "1");
                map.put("tablename", "");
                map.put("trowkey", "");
                map.put("columns", "");
                map.put("indextablename", "");
                map.put("irowkey", "");
                map.put("icolumns", "");
            } finally {
                request.setAttribute("map", map);
                return "savedata/index";
            }

        }

    只要通过这个方法跳向得页面都是随机生成一个token,然后再真正再提交触发得方法上加入@token(remove=true),贴代码:

    @RequestMapping("/SaveDataController/saveData")
        @ResponseBody
        @Token(remove=true)
        public void saveData(HttpServletRequest request,HttpServletResponse response,
                             String tablename,String trowkey,String columns,
                             String indextablename,String irowkey,String icolumns,
                             String task_id,String savetype,String memoryCodes){
            System.out.println(task_id);
            saveDataService.saveData(task_id,savetype,memoryCodes,tablename, trowkey, columns, indextablename, irowkey, icolumns);

        }

    上面的只能防止单页面的重复提交,如果同时打开两个页面同时进行提交,则第二次提交总是失败,需要进行再次扩展,具体方法如下:

    但是--

    如果打开两个标签页,则这两个页面分别有一个token,并且是不同的(理论上是不同的),但是session中只有一份,

    其中一个提交后,就会删除session中的token,那么另外一个页面提交时session中的token已为空,那么一定校验不通过.

    根本原因:

    在同一时刻,session中只存了一份token,而页面上可能有多个token(有n个页签,就会有n个不同的token).

    既然找到了根本原因,那么也就自然而然产生了解决方案.

    思路:session中不能只存储一份token,而是支持存储多个token

    具体技术方案:

    (1)每次进入下单页都会产生一个新的token,这个token都进入两个数据流:

    --(a)传到页面,key是repeattoken

    前端页面引用方式:

    Html代码  
    1. <input type="hidden" name="repeattoken" value="${Session.repeattoken!}" >  

     

     

    --(b)存储到session(现在是增量,不会把原来的token替换掉)

    (2)存储到session中的key应该与页面的key区分开来,使用"tokenpool"

    优化之后的过滤器:

    Java代码   收藏代码
    1. package com.chanjet.gov.filter;  
    2.   
    3. import com.chanjet.gov.util.StringUtil;  
    4. import org.apache.log4j.Logger;  
    5. import org.springframework.web.method.HandlerMethod;  
    6. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;  
    7.   
    8. import javax.servlet.http.HttpServletRequest;  
    9. import javax.servlet.http.HttpServletResponse;  
    10. import javax.servlet.http.HttpSession;  
    11. import java.lang.reflect.Method;  
    12. import java.util.UUID;  
    13.   
    14. /** 
    15.  *     防止下单页重复提交 
    16.  */  
    17. public class RepeatTokenInterceptor  extends HandlerInterceptorAdapter {  
    18.     /*** 
    19.      * 用于前端页面接收服务器端的token 
    20.      */  
    21.     public static final String SESSION_KEY_REPEATTOKEN="repeattoken";  
    22.     /*** 
    23.      * 用于session存储n个token 
    24.      */  
    25.     public static final String SESSION_KEY_REPEATTOKEN_POOL = "tokenpool";  
    26.     private static Logger log = Logger.getLogger(RepeatTokenInterceptor.class);  
    27.   
    28.     private void addRepeatToken(HttpServletRequest request, HttpServletResponse response){  
    29.         HttpSession httpSession = request.getSession(true);  
    30.         String token = (String) httpSession.getAttribute(SESSION_KEY_REPEATTOKEN_POOL);  
    31.         System.out.println("addRepeatToken token:"+token);  
    32.         String createdToken = UUID.randomUUID().toString();  
    33.         httpSession.setAttribute(SESSION_KEY_REPEATTOKEN, createdToken);//给前端页面用的  
    34.         if(StringUtil.isNullOrEmpty(token)){  
    35.             httpSession.setAttribute(SESSION_KEY_REPEATTOKEN_POOL, createdToken);  
    36.         }else{  
    37.             httpSession.setAttribute(SESSION_KEY_REPEATTOKEN_POOL, createdToken + "###" + token);  
    38.         }  
    39.     }  
    40.     private void removeRepeatToken(HttpServletRequest request, HttpServletResponse response){  
    41.         HttpSession httpSession = request.getSession(true);  
    42.         String token = (String) httpSession.getAttribute(SESSION_KEY_REPEATTOKEN_POOL);  
    43.         System.out.println("removeRepeatToken token:"+token);  
    44.         if(!StringUtil.isNullOrEmpty(token)){  
    45.             String clientToken = (String) request.getParameter(SESSION_KEY_REPEATTOKEN);  
    46.             System.out.println("removeRepeatToken serverToken:"+clientToken);  
    47.             if (clientToken == null) {  
    48.                 return;  
    49.             }  
    50.             token = token.replace(clientToken, "").replace("######""###");  
    51.             System.out.println("token:"+token);  
    52.             httpSession.setAttribute(SESSION_KEY_REPEATTOKEN_POOL, token);  
    53.         }  
    54.     }  
    55.     @Override  
    56.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
    57.         if (handler instanceof HandlerMethod) {  
    58.             HandlerMethod handlerMethod = (HandlerMethod) handler;  
    59.             Method method = handlerMethod.getMethod();  
    60.             RepeatSubmitToken annotation = method.getAnnotation(RepeatSubmitToken.class);  
    61.             if (annotation != null) {  
    62.                 boolean needSaveSession = annotation.save();  
    63.                 if (needSaveSession) {  
    64.                     addRepeatToken(request,response);  
    65.                 }  
    66.                 boolean needRemoveSession = annotation.remove();  
    67.                 if (needRemoveSession) {  
    68.                     if (isRepeatSubmit(request)) {  
    69.                         log.warn("please don't repeat submit,url:" + request.getServletPath());  
    70.                         response.sendRedirect("/warn.html?code=repeatSubmitOrder&orgId="+request.getParameter("orgId"));  
    71.                         return false;  
    72.                     }  
    73.                     removeRepeatToken(request,response);  
    74.                 }  
    75.             }  
    76.             return true;  
    77.         } else {  
    78.             return super.preHandle(request, response, handler);  
    79.         }  
    80.     }  
    81.   
    82.     private boolean isRepeatSubmit(HttpServletRequest request) {  
    83.         //从池子里面获取token  
    84.         String serverToken = (String) request.getSession(true).getAttribute(SESSION_KEY_REPEATTOKEN_POOL);  
    85.         if (serverToken == null||"###".equals(serverToken)) {  
    86.             return true;  
    87.         }  
    88.         String clinetToken = request.getParameter(SESSION_KEY_REPEATTOKEN);//请求要素  
    89.         if (StringUtil.isNullOrEmpty(clinetToken)) {  
    90.             return true;  
    91.         }  
    92.         System.out.println("clinetToken:"+clinetToken);  
    93.         if (!serverToken.contains(clinetToken)) {  
    94.             return true;  
    95.         }  
    96.         return false;  
    97.     }  
    98. }  




    展开全文
  • 前端在向后端进行数据提交的时候,通常会需要在第一次提交返回前,阻止用户在快速点击发送二次请求,即防止重复提交,最简单的方法是使用标志参数或者 class 元素控制,但缺点是,每个控制重复提交的地方都需要加上...

    背景

    前端在向后端进行数据提交的时候,通常会需要在第一次提交返回前,阻止用户在快速点击发送二次请求,即防止重复提交,最简单的方法是使用标志参数或者 class 元素控制,但缺点是,每个控制重复提交的地方都需要加上这个逻辑,重复性太强,且控制逻辑不统一。

    目前前端使用的是http协议,所以提交方式为两种

    • 异步提交,使用jQuery.ajax()
    • form 表单同步提交

    异步防重复提交的方案如下

    通过 jQuery 提供的 ajaxPrefilter 方法,将在请求提交之前进行过滤,仅保留第一次请求,后续的请求 abort 阻止掉,具体实现代码如下

    /**
     * _pendingRequests = {
     *  'http:xxx.xxxx.do':['domain=P2P','xxxx=aaa'],
     *  'http:xxx.yyyy.do':['domain=P3P','xxxx=bbb']
     * }
     * 该对象的 key 是请求的 url ,value 是由请求参数转化成的字符串数组
     */
    var _pendingRequests = {};
    $.ajaxPrefilter(function(options, originalOptions, jqXHR) {
        var p_item = {  //保存请求请求的url
                key:options.url,
                index:0
            },
            dataArray = options.data ? options.data.split('&') : [];
            compareData = function(beforD,afterD) {
                //当url相同时,以此比较保存的参数对象,若参数对象相同,则返回false,若第一个就相同,则跳出循环
                // 反之说明当前参数对象列表中没有与将要提交的参数相同,则可看为不同的请求,返回true,允许发起请求
                var result  = false;
                for(var i=0;i<beforD.length;i++){
                    if(beforD[i]){
                        result = false;
                        var beforData = beforD[i];
                        for(var j=0;j<beforData.length;j++){
                            if(afterD[j] !== beforData[j]){
                                result = true;
                                break;
                            }
                        }
                        if (!result){
                            break;
                        }
                    }else {
                        result = true;
                        continue;
                    }
                }
                return result;
            };
    
        //若请求队列中不存在或者同一个请求不同参数,且不为html后缀,则加入队列中
        if (( !_pendingRequests[p_item.key] || compareData(_pendingRequests[p_item.key],dataArray) ) && p_item.key.indexOf('.html') === -1) {
            //给 index 赋值是因为请求是异步返回的,index用于标记第一个请求
            if(_pendingRequests[p_item.key]){
                p_item.index = _pendingRequests[p_item.key].push(dataArray)-1;
            } else{
                _pendingRequests[p_item.key] = [dataArray];
                p_item.index = 0;
            }
        } else if (p_item.key.indexOf('.html') === -1) {
            jqXHR.abort();	// 放弃后触发的重复提交,仅保留第一次提交
            //pendingRequests[key].abort();	// 放弃先触发的提交
        }
        var complete = options.complete;
        //请求完成
        options.complete = function(jqXHR, textStatus) {
            // 通过 key 和 index 获取成功返回的请求,将其值为 null ,下一次该请求便是在请求队列中便是新的一个请求
            _pendingRequests[p_item.key][p_item.index] = null;
            if ($.isFunction(complete)) {
                complete.apply(this, arguments);
            }
        };
    });
    
    复制代码

    jquery.ajaxprefilter官方文档

    表单提交防重复提交的方案如下

    表单的处理就稍微要麻烦点,但大致思路和异步的相同,等待第一次请求返回的同时,阻止后续触发的请求发送 首先基于jquery扩展了一个自定义的方法,如下

    $.fn.preventDoubleSubmission = function() {
        $(this).on('submit', function(e) {
            var $form = $(this);
            // $form.data('submitted') 通过该变量判断请求的状态
            if ($form.data('submitted') === true) {
                //阻止请求
                e.preventDefault();
            } else {
                $form.data('submitted', true);
                if ($form.attr('target') === '_blank') {
                    setTimeout(function() {
                        $form.data('submitted', false);
                    }, 800);
                }
            }
        });
        return this;
    };
    
    复制代码

    当表单初次提交时,通过 jQuery.data() 设置一个标志位,当表单重复提交时,判断设置的标志位,若是提交状态,将阻止表单的提交事件。当form.target = _blank 提交后打开新界面的情况,将在800毫秒后恢复原界面表单可提交状态。

    为了方便对全站的表单提交统一处理,可对需要放重复提交的表单添加一个class preventDouble,在页面渲染后,统一加上事件监听

    //扫描带有 preventDouble 标识的form表单
    $(function() {
        var f = $('.contain form.preventDouble');
        for (var i=0;i<f.length;i++){
            $(f[i]).preventDoubleSubmission();
        }
    });
    复制代码

    小贴士

    提交按钮需使用 type=’submit’ ,因为监听的是表单的submit事件 不建议多次监听submit事件,会导致放重复提交失效 在表单提交前通常会有些表单检验的操作,所以当校验失败的时候,可以通过 event.preventDefault() 阻止表单提交

    展开全文
  • ThinkPHP官方防止表单重复提交文档 前端提交页面 添加token方法 {:token()} 或者在提交页面使用 <input type="hidden" name="__token__" value="{$Request.token}" /> 在处理提交方法的 方法里 验证 添加...
  • php 防止表单重复提交 由于网络原因,经常出来点了提交按钮,网页没有反应,而进行再次点击。这样就导致后台收到两次提交,从而进行两次处理,本文章向大家介绍php 防止表单重复提交的几种方法 1、前端解决 方法一:...
  • 在公司后台做表单提交,一是自己员工用,二是 html 自己来写的,没有验证表单重复提交,结果出错了。写出来记录下以便提醒自己,时刻不能疏忽。 解决方法 其实方法有很多种,只举例几个简单的来说说。 框架 很多框架...
  • 在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交。 1、表单...
  • 我们大家再进行web开发的时候,必不可少会遇见表单重复提交问题。今天就来给总结如何解决表单提交问题,欢迎大家交流指正。 首先我们在讨论如何解决表单重复提交问题之前先来解决三个问题:1.什么叫表单重复提交?...
  • 在加载时添加下面两条语句 protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { #region 遮罩按钮 this.Download.Attributes.Add(" onclick ", ClientScript....
  • 产生原因:网络延时、重新刷新、点击浏览器的【后退】按钮回退到表单页面后...模拟程序使用验证码模拟请求识别验证码是非常难token+验证码使用 javascript 解决既然存在上述所说的表单重复提交问题,那么我们就要想...
  • 在Web开发中,对于处理表单重复提交是经常要面对的事情。那么,存在哪些场景会导致表单重复提交呢?表单重复提交会带来什么问题?有哪些方法可以避免表单重复提交表单重复提交的场景 1.场景一:服务端未能及时...
  • 用户在提交表单的过程中,由于网络等原因,可能重复点击提交按钮,向数据库重复写入或者读取数据,...2.服务端防止表单重复提交,在servlet中限制。 a.由程序产生表单 程序生成一个token值通过session存储 pack...
  • SpringMVC防止表单重复提交(拦截器实现)        之前项目中在表单提交的时候由于网络原因造成响应慢,用户会重复点击,造成新增或修改时数据库产生脏数据,首先想到的解决方式...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,463
精华内容 3,785
关键字:

前端防止表单重复提交