如何防止ajax post请求提交两次?

时间:2021-03-02 05:56:30

标签: javascript jquery ajax laravel

我有一个按钮订阅,它应该通过 ajax 向我的控制器提交一个发布请求以插入到我的表中。

我的观点是这样的:

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8">
            <div class="flash-message"></div>
            <div class="card">
                <div class="card-header">
                    <div class="level">
                        <span class="flex"><a href="{{route('profile',$thread->creator->name)}}">{{$thread->creator->name}}</a> posted:
                            {{$thread->title}}
                        </span>
                        @if(auth()->check())
                        @if($subscription)
                        <button class="btn btn-secondary" id="unsubscribe">Unsubscribe</button>
                        @else
                        <button class="btn btn-danger" id="subscribe">Subscribe</button>
                        @endif
                        @endif
                        @can('update',$thread)
                        <a href="{{$thread->path()}}/edit" class="btn btn-link">Edit Thread</a>
                        <form action="{{$thread->path()}}" method="POST">
                            @csrf
                            @method('delete')
                            <button class="btn btn-link" type="submit">Delete Thread</button>
                        </form>
                        @endcan
                    </div>
                </div>
                <div class="card-body">
                {{$thread->body}}
                </div>
            </div>

..............

我的 app.blade:

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>

    <!--jQuery/share.js -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha256-4+XzXVhsDmqanXGHaHvgh1gMQKX40OUvDEBTu8JcmNs=" crossorigin="anonymous"></script>
    <script src="{{ asset('js/share.js') }}"></script>

    <!-- Fonts -->
    <link rel="dns-prefetch" href="//fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">

    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
    <style>
        body{
            padding-bottom:100px;
        }
        .level{
            display: flex;
            align-items: center;
        }
        .flex{
            flex: 1;
        }
    </style>
</head>
<body>
      <div id="app">
        @include('layouts.nav')
        <main class="py-4">
            @yield('content')
        </main>
    <flash message="{{session('flash')}}"></flash>
    </div>
</body>

<style>
    .btn-width{
        min-width: 70px;
      }
</style>


</html>

调用按钮的代码:

<script type="application/javascript">

    $(document).ready(function(){
        $('#subscribe').click(function(e){
            e.preventDefault();
            $.ajaxSetup({
                  headers: {
                      'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                  }
              });
              
            $.ajax({
                url: "{{route('subscription.store')}}",
                method:'POST',
                data: {
                    thread_id: "{{$thread->id}}",
                },
                success:function(response){
                    $('div.flash-message').html(response);
                   
                },
                error:function(error){
                    console.log(error);
                }
            });
        });
    });
据我所知,没有其他元素与我的按钮共享相同的 ID。而且,我的按钮不在表单提交中,因此不应调用两次。检查开发工具没有显示错误,并且在网络选项卡中,两个请求被相同的发起者调用。

所以,我有点想知道为什么会发生这种情况。 ajax post 请求不应该只提交一次请求吗?

我真的很想深入了解这个问题,因为大多数其他类似问题都调用了两次提交,而我的代码只应该调用一次。相反,它对我的​​数据库进行了两次插入。

我还能做些什么来找出问题的根本原因?

4 个答案:

答案 0 :(得分:1)

您的 javascript 是否有可能以某种方式加载了两次?这将附加两个相同的侦听器,并在单击时发送两次请求。如果您将 console.log 放在事件处理程序中,您是否也看到了两倍?

此外,显然,.click 为与传递给 jQuery 对象的选择器匹配的每个元素添加了一个单独的事件侦听器,而 .on only adds a single one.。如果你改为这样做会发生什么?

$(document).ready(function () {
  $("#subscribe").on("click", function(e) {
    e.preventDefault();
    $.ajaxSetup({
      headers: {
        "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
      },
    });

    $.ajax({
      url: "{{route('subscription.store')}}",
      method: "POST",
      data: {
        thread_id: "{{$thread->id}}",
      },
      success: function (response) {
        $("div.flash-message").html(response);
      },
      error: function (error) {
        console.log(error);
      },
    });
  });
});

答案 1 :(得分:0)

你调用你的函数两次,一个是在文档准备好,另一个是在按钮点击移除文档

答案 2 :(得分:0)

你试过给 return false 吗?像这样:

$(document).ready(function(){
    let subscribeClick = function() {
     $.ajaxSetup({
              headers: {
                  'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
              }
          });
          
        $.ajax({
            url: "{{route('subscription.store')}}",
            method:'POST',
            data: {
                thread_id: "{{$thread->id}}",
            },
            success:function(response){
                $('div.flash-message').html(response);
               
            },
            error:function(error){
                console.log(error);
            }
        });
        return false;
    }
    $('#subscribe').click(function(e){
        e.preventDefault();
        e.stopImmediatePropagation();
        subscribeClick(); 
    });
});

答案 3 :(得分:0)

您可以尝试以下选项:

(1) 在你的 ajax 调用中使用 async: false 来停止其他代码的执行,直到你收到当前 ajax 调用的响应。

 $('#subscribe').click(function(e) {
    e.preventDefault();
    $.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });

    $.ajax({
        url: "{{route('subscription.store')}}",
        method: 'POST',
        async: false,
        data: {
            thread_id: "{{$thread->id}}",
        },
        success: function(response) {
            $('div.flash-message').html(response);

        },
        error: function(error) {
            console.log(error);
        }
    });
});

(2) 您可以使用 Event 接口的 stopPropagation() 方法,以防止当前事件在捕获和冒泡阶段进一步传播。

$('#subscribe').click(function(e) {
    e.preventDefault();
    e.stopPropagation();
    $.ajaxSetup({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });

    $.ajax({
        url: "{{route('subscription.store')}}",
        method: 'POST',
        async: false,
        data: {
            thread_id: "{{$thread->id}}",
        },
        success: function(response) {
            $('div.flash-message').html(response);

        },
        error: function(error) {
            console.log(error);
        }
    });
});

(3) 使用存储请求状态的变量。

var isLoading = false;
$(document).ready(function() {
    $('#subscribe').click(function(e) {
        if (!isLoading ) { 
            isLoading = true; //make true when request starts
            e.preventDefault();
            $.ajaxSetup({
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                }
            });

            $.ajax({
                url: "{{route('subscription.store')}}",
                method: 'POST',
                data: {
                    thread_id: "{{$thread->id}}",
                },
                success: function(response) {
                    $('div.flash-message').html(response);
                    isLoading = false; //make false when response is received
                },
                error: function(error) {
                    console.log(error);
                    isLoading = false; //make false when error is received
                }
            });
        }
    });
});
相关问题