フォームがクライアント側から複数回送信されないようにするにはどうすればよいですか?


96

応答が遅い場合、送信ボタンを複数回クリックすることがあります。

これを防ぐ方法は?


4
質問のタイトルに「クライアント側」を置く理由は、複製の送信を試みて回避するためのクライアントでの解決策はすべて100%安全ではなく、常にサーバー側で検証を行う必要があることを知っているためです。
Paolo Bergantino、

51
Paolo:はい、完全なデータセキュリティに関心がある場合は、サーバー側で行う必要があります。ただし、シングルクリックのみが必要な場合に、おばあちゃんが送信ボタンをダブルクリックしないようにしたい場合もあります。これらの場合、JavaScriptは完全に問題ありません。
Simon East

1
サーバー側でのみ実行しても、100%安全ではありません。最初の要求が完了するまでに時間がかかり、2番目の要求が続行しないことがわかるためです。
igorsantos07 2015年

CSRF攻撃を防ぐためのCookie二重送信パターンは、複数のフォームの送信も防ぎませんか?
Martin Thoma

回答:


99

控えめなJavaScriptを使用して、フォームがすでに送信された後にフォームの送信イベントを無効にします。jQueryを使用した例を次に示します。

編集:送信ボタンをクリックせずにフォームを送信する際の問題を修正しました。ありがとう、いちばん。

$("body").on("submit", "form", function() {
    $(this).submit(function() {
        return false;
    });
    return true;
});

4
テキストボックスでEnterキーを押してフォームを送信するとどうなりますか?
ichiban

2
あなたも必要return trueですか?最初の提出はそれなしでもうまくいくと思います。
Simon East、

return true省略された場合、それが暗示されると思います。
デレク

15
控えめな検証とMVCでこのソリューションを試しました。JSが最初に呼び出され、常にfalseを返し、次に検証が呼び出されます。したがって、フォームに検証エラーがある場合、フォームは送信されません。
bjan

6
本当に素晴らしい作品です。また、送信ボタンを無効にし、送信ボタンのテキストを置き換えて、ユーザーのヒントも表示するようにします。$(this).find("input[type='submit']").attr('disabled', 'disabled').val('submiting'); return true; });
カム・ソング

42

vansteeのソリューションをasp mvc 3の控えめな検証とともに試しましたが、クライアントの検証が失敗した場合でもコードは実行され、フォームの送信は完全に無効になります。フィールドを修正した後、再送信できません。(bjanのコメントを参照)

そこで、vansteeのスクリプトを次のように変更しました。

$("form").submit(function () {
    if ($(this).valid()) {
        $(this).submit(function () {
            return false;
        });
        return true;
    }
    else {
        return false;
    }
});

注意すべき他の副作用、またはこれはあなたがどこにでも適用できるようにうまくいきましたか?
Ciaran Gallagher

24

onsubmitハンドラーで送信ボタンを非表示にし、それを読み込みアニメーションに置き換えることで、クライアント側のフォーム送信コントロールを非常にエレガントに実現できます。そうすることで、ユーザーはアクション(クリック)が発生したのと同じ場所で即座に視覚的なフィードバックを得ることができます。同時に、フォームが再度送信されるのを防ぎます。

XHRを介してフォームを送信する場合は、タイムアウトなどの送信エラーも処理する必要があることに注意してください。ユーザーフォーム再送信する必要があるため、送信ボタンを再度表示する必要があります。

別のメモでは、llimllibは非常に有効なポイントを提示します。すべてのフォーム検証はサーバー側で行う必要があります。これには、複数の送信チェックが含まれます。クライアントを信頼しないでください!これは、JavaScriptが無効になっている場合だけではありません。すべてのクライアント側コードは変更できることに注意してください。想像するのは少し難しいですが、サーバーと通信するhtml / javascriptが必ずしも作成したhtml / javascriptであるとは限りません。

llimllibが示すように、そのフォームに固有の識別子を使用してフォームを生成し、非表示の入力フィールドに配置します。その識別子を保存します。フォームデータを受信するときは、識別子が一致する場合のみ処理します。(また、識別子をユーザーセッションにリンクし、セキュリティを強化するためにそれを照合します。)データ処理後、識別子を削除します。

もちろん、時々、フォームデータが送信されていない識別子をクリーンアップする必要があります。しかし、おそらくあなたのウェブサイトはすでに何らかの「ガベージコレクション」メカニズムを採用しています。


15
<form onsubmit="if(submitted) return false; submitted = true; return true">

6
次のエラーを回避するには、を使用する<form onsubmit="return (typeof submitted == 'undefined') ? (submitted = true) : !submitted">var submitted = false;、スクリプトの適切な場所に書き込みますUncaught ReferenceError: submitted is not defined
タマシュBolvári

15

これを行う簡単な方法を次に示します。

<form onsubmit="return checkBeforeSubmit()">
  some input:<input type="text">
  <input type="submit" value="submit" />
</form>

<script type="text/javascript">
  var wasSubmitted = false;    
    function checkBeforeSubmit(){
      if(!wasSubmitted) {
        wasSubmitted = true;
        return wasSubmitted;
      }
      return false;
    }    
</script>

検証エラーがある場合はjQueryの控えめな検証と、スクリプトブロックは、第一および検証まったく提出をもたらしていないその隣に呼び出される
bjan

8

クリック後すぐに送信ボタンを無効にします。検証を適切に処理するようにしてください。また、すべての処理またはDB操作の中間ページを保持してから、次のページにリダイレクトします。これは、2番目のページを更新しても別の処理が行われないことを確認します。


ええ、すごいヒント、Shoban。する必要がありますform page ---submits to---> form_submission_script.php ---after saving, redirects to---> form_thankyou.html
サイモンイースト

6

現在の時間をハッシュし、フォーム上の非表示の入力にします。サーバー側で、各フォーム送信のハッシュを確認します。そのハッシュをすでに受け取っている場合は、繰り返し送信されます。

編集:javascriptに依存することは良い考えではないので、すべての人がそれらの考えを支持し続けることができますが、一部のユーザーはそれを有効にしません。正解は、サーバー側のユーザー入力を信頼しないことです。


これは「多すぎる」ように見えませんか?;-)
ショーバン、

1
これは、ユーザーが1秒間に2回以上フォームを送信できないようにするだけのようです。2009-05-29 12:13:37でフォームを送信すると、サーバーは同じハッシュで別のフォームを送信できませんが、[2009-05-29 12:13:38で送信]をクリックすると、それは通り抜けます。また、この手法では、2人の異なるユーザーが2つの異なるフォームを同時に送信するのを防ぐことができます。
サラ船

2
@moneypenny最初の異議はfalseです。ハッシュは、フォームがユーザーに送信された時間ではなく、ユーザーに送信された時間です。2番目の問題が本当に心配な場合は、選択肢がたくさんあります。ハッシュする文字列にセッションIDを追加するか、フォームのすべてのフィールドが正確に同じかどうかを確認します。2人のユーザーがまったく同じフォームを送信しなかった可能性があります。
llimllib 2009年

@Shobanごめんなさい、私はあなたの言っていることには従いません
llimllib 2009年

2
「過剰」は見る人の目にあります。あなたがいる場合、実際に重複したフォームの送信を防ぐために必要な、液の少なくとも一部は、サーバー側である必要があります。「ユーザーを信用することはできません。」
ベンブランク

5

進行状況バーまたはスピナーを表示して、フォームが処理中であることを示すこともできます。


5

JQueryを使用すると、次のことができます。

$('input:submit').click( function() { this.disabled = true } );

   $('input:submit').keypress( function(e) {
     if (e.which == 13) {
        this.disabled = true 
     } 
    }
   );

1
ボタンが無効になった後、テキストボックスでEnterキーを押してフォームを送信するとどうなりますか?
いちばん

このようにボタンを無効にすると、ユーザーはEnterキーを押すことができなくなります。ただし、送信入力にキープレスをバインドする必要があります
BorisGuéry'29年

これにより、ボタンを送信できなくなります。したがって、サーバー側の検証を無効にします。
MarkoAleksić11年

@Marko、そうですが、それはOPが要求するものです。とにかくトークンを使用すると、フォームが2回送信されるのを防ぐことができます。
BorisGuéry11年

1
この種の手法を試したところ、フォームがまったく送信されないことがわかりました(少なくともChrome 14では)。ブラウザがフォームの送信を開始する前にボタンを無効にしたためと考えられます。
Simon East、

4

質問に「JavaScript」のタグを付けたのは知っていますが、JavaScriptにまったく依存しない解決策を次に示します。

これはPRGという名前のwebappパターンであり、これを説明する良い記事です


4

あなたは単純に複数の送信を防ぐことができます:

var Workin = false;

$('form').submit(function()
{
   if(Workin) return false;
   Workin =true;

   // codes here.
   // Once you finish turn the Workin variable into false 
   // to enable the submit event again
   Workin = false;

});

あなたの答えの問題は、ユーザーがクリックした時間と時間の間が一瞬であることWorkin =true;です。二重提出はまだ可能ですが、それよりも少ない可能性があります。
sent1nel 2014

4

この質問に対する最も単純な答えは、「応答が遅い場合、送信ボタンを複数回クリックすることがあります。これを防ぐにはどうすればよいですか?」

以下のコードのように、フォームの送信ボタンを無効にするだけです。

<form ... onsubmit="buttonName.disabled=true; return true;">
  <input type="submit" name="buttonName" value="Submit">
</form>

送信のための最初のクリックで送信ボタンを無効にします。また、いくつかの検証ルールがある場合は、正常に機能します。それがお役に立てば幸いです。


何か不足していると思うので、コードを投稿してください。
Imran Khan

3

クライアント側では、@ vansteeや@chaosが提供するメソッドのように、JavaScriptコードを使用してフォームを送信したら、送信ボタンを無効にする必要があります。

ただし、これが発生するのを防ぐためにJSに依存してはならないネットワークラグまたはJavaScriptが無効な状況には問題があります。

そのため、サーバー側では、同じクライアントからの繰り返し送信を確認し、ユーザーからの誤った試みと思われる繰り返しの送信を省略する必要があります。


私はこれがずっと前に回答されたことを知っていますが、誰かがネットワークの遅れが無効化をどのように防ぐことができるかを説明できますか?私は現在この問題を扱っており、ボタンを無効にしてもフォームが二重に送信される方法について非常に混乱しています。JavaScriptを無効にすることすら考えたこともありませんでした。私の場合それは問題ではないと思いますが、それでも興味深い見識です。
davidatthepark

クリックハンドラーの調整も検討していました。
davidatthepark

3

safeform jqueryプラグインを試すことができます。

$('#example').safeform({
    timeout: 5000, // disable form on 5 sec. after submit
    submit: function(event) {
        // put here validation and ajax stuff...

        // no need to wait for timeout, re-enable the form ASAP
        $(this).safeform('complete');
        return false;
    }
})

1

私にとって最もシンプルでエレガントなソリューション:

function checkForm(form) // Submit button clicked
{
    form.myButton.disabled = true;
    form.myButton.value = "Please wait...";
    return true;
}

<form method="POST" action="..." onsubmit="return checkForm(this);">
    ...
    <input type="submit" name="myButton" value="Submit">
</form>

詳細はリンク...


1

form.itでこのコードを使用して、複数のクリックを処理します。

<script type="text/javascript">
    $(document).ready(function() {
        $("form").submit(function() {
            $(this).submit(function() {
                return false;
            });
            return true;
        });     
    }); 
</script>

それは確かに動作します。


1

これにより、2秒ごとに送信できます。フロント検証の場合。

$(document).ready(function() {
    $('form[debounce]').submit(function(e) {
        const submiting = !!$(this).data('submiting');

        if(!submiting) {
            $(this).data('submiting', true);

            setTimeout(() => {
                $(this).data('submiting', false);
            }, 2000);

            return true;
        }

        e.preventDefault();
        return false;
    });
})

0

複数が送信されないようにする最良の方法は、メソッドでボタンIDを渡すだけです。

    function DisableButton() {
        document.getElementById("btnPostJob").disabled = true;
    }
    window.onbeforeunload = DisableButton; 

0

JavaScriptを使用してこれを行うのは少し簡単です。以下は、必要な機能を提供するコードです。

$('#disable').on('click', function(){
    $('#disable').attr("disabled", true);
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="disable">Disable Me!</button>


0

最も単純な解決策は、クリック時にボタンを無効にし、操作の完了後に有効にすることです。jsfiddleで同様のソリューションを確認するには:

[click here][1]

そして、あなたはこの答えでいくつかの他の解決策を見つけることができます。


1
リンクはすばらしいですが、回答には実際に回答が含まれるため、リンクにコンテキストを提供してください外部サイトへのリンク以上のものであることが、なぜ、どのようにして一部の回答が削除されるのかについて考えられる理由に注意してください
1

0

これは私にとって非常にうまく機能します。ファームを送信してボタンを無効にし、2秒後にボタンをアクティブにします。

<button id="submit" type="submit" onclick="submitLimit()">Yes</button>

function submitLimit() {
var btn = document.getElementById('submit')
setTimeout(function() {
    btn.setAttribute('disabled', 'disabled');
}, 1);

setTimeout(function() {
    btn.removeAttribute('disabled');
}, 2000);}

ECMA6 Syntex内

function submitLimit() {
submitBtn = document.getElementById('submit');

setTimeout(() => { submitBtn.setAttribute('disabled', 'disabled') }, 1);

setTimeout(() => { submitBtn.removeAttribute('disabled') }, 4000);}

0

ブラウザーの入力検証をバイパスせずに、可能な回答に追加するだけです

$( document ).ready(function() {
    $('.btn-submit').on('click', function() {
        if(this.form.checkValidity()) {
            $(this).attr("disabled", "disabled");
            $(this).val("Submitting...");
            this.form.submit();
        }
    });
});

0

以前に提案されたものに代わるものは次のとおりです。

jQuery('form').submit(function(){
     $(this).find(':submit').attr( 'disabled','disabled' );
     //the rest of your code
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.