フォームの再送信の防止


107

ページ1にはHTMLフォームが含まれています。2ページ-送信されたデータを処理するコード。

1ページ目のフォームが送信されます。ブラウザは2ページにリダイレクトされます。2ページ目は送信されたデータを処理します。

この時点で、ページ2が更新されると、「フォームの再送信の確認」アラートがポップアップします。

これを防ぐことはできますか?



3
ここで説明されているようにポストリダイレクトgetを使用します->> en.wikipedia.org/wiki/Post/Redirect/Get
Meer

リダイレクトせずにそれを防ぐことができます。見てここに
オイゲン・Konkov

回答:


145

ここでは、2つのアプローチが使用されています。

方法1: AJAX +リダイレクトを使用する

このようにして、JQueryまたはPage2に似たものを使用してフォームをバックグラウンドで投稿しますが、ユーザーにはまだpage1が表示されます。投稿が成功したら、ブラウザをPage2にリダイレクトします。

方法2:投稿+自分にリダイレクト

これはフォーラムで一般的な手法です。Page1のフォームはデータをPage2に送信し、Page2はデータを処理して必要な処理を実行し、それ自体でHTTPリダイレクトを実行します。このように、ブラウザが覚えている最後の「アクション」はpage2の単純なGETなので、フォームはF5で再送信されません。


2
方法2の変形は、別のページへのリダイレクトです。たとえば、example.com / save.htmlに POSTし、保存が完了すると、example.com/list.htmlにリダイレクトします
Guillaume、

1
方法1では、BlockUIという名前のjQueryプラグインを使用して、何かが起こっていることをクライアントに知らせます。
霧雨

方法2を使用していますが、更新した場合は再送信するように求められます。これと同様の問題を抱えている人はいますか?
熱心

HTTPリダイレクトが正しく機能していることを確認しますか?ネットワークインスペクター/ firebug /を使用して、ブラウザーが発信HTTP要求を検査し、HTTP呼び出しをチェックします。最初のクエリ(フォームデータの投稿)がPOSTメソッドで発生し、Locationヘッダーがそれ自体を指すHTTPコード301を返し、すぐにGETメソッドで同じページへの別のHTTPクエリが表示されるはずです。
CodeTwice 2013

@CodeTwice:私の場合、page1がpage2に投稿し、page2がデータを処理してページを表示します(値はテンプレートに渡されます)。リダイレクトはどこで発生しますか?..ページにはGETリクエストがありません。
user1050619 2014年

24

PRG-Post / Redirect / Getパターンを使用する必要があり、PRGのPを実装したところです。リダイレクトする必要があります(現在、リダイレクトはまったく必要ありません。これを参照してください)

PRGは、フォーム送信の重複を防ぐWeb開発設計パターンです。つまり、フォームの送信(要求1の後)->リダイレクト->取得(要求2)です。

Under the hood

リダイレクトステータスコード -HTTP 1.0とHTTP 302またはHTTP 1.1とHTTP 303

リダイレクトステータスコードを含むHTTP応答は、ロケーションヘッダーフィールドにURLを追加で提供します。ユーザーエージェント(Webブラウザーなど)は、このコードを含む応答によって招待され、場所フィールドで指定された新しいURLに2番目の、それ以外は同一の要求を行います。

リダイレクトステータスコードは、この状況で、最初のHTTP POSTリクエストが再送信されることなく、Webユーザーのブラウザーがサーバーの応答を安全に更新できるようにするためのものです。

Double Submit Problem

二重送信の問題

Post/Redirect/Get Solution

投稿/リダイレクト/ソリューションの取得

ソース


2
良い説明。リダイレクトが行われた後、ユーザーがブラウザーの[戻る]ボタンをクリックするとどうなるのだろう。「フォーム再送信の確認」ポップアップが再び表示されますか?確認ポップアップが再度表示されない場合でも、同じデータを使用してページ1に投稿リクエストが再度行われ、ユーザーは再びページ2にリダイレクトされます。一連のフォームform1、form2、form3があります。フォーム「n」からフォーム「n-1」にシームレスに戻る方法 ランダム質問:あなたはPRGデザインパターンを勉強しました
Rpant

@Rpant on chromeを使用すると、ロケーションヘッダーを送信するphpファイルがブラウザーの履歴に表示されないため、[戻る]ボタンをクリックするとフォームに戻るだけです。
FluorescentGreen5

@Angelinリダイレクト後、getはどのようにデータを取得しますか?たとえば、/ some_urlにデータを投稿し、GETリクエストを行う/ some_urlにリダイレクトする場合。/ some_urlは汎用的で、/ some_url / <id>のようなIDを含んでいないので、どのように応答すればよいかを知るにはどうすればよいですか?
Amit Tripathi 2017

@AmitTripathiあなた自身を作成する必要があります。例:POSTリクエストは顧客データを挿入するものであり、GETは正常に挿入されたデータを表示するものです。データベースへの挿入が成功した後に受け取った顧客IDによって、その顧客のデータベースからフェッチすることにより、フォームデータであるだけでデータを表示したり、顧客ページのビューを再利用したりできます。
アンジェリンナダル

しかし、私は@Eugen Konkovソリューションに同意します
アンジェリンナダル

10

直接はできません。それは良いことです。ブラウザのアラートは、理由があります。このスレッドはあなたの質問に答えるべきです:

戻るボタンにPOST確認アラートが表示されないようにする

推奨される2つの主要な回避策は、PRGパターンと、AJAX送信とそれに続くスクリプトの再配置です。

メソッドがPOST送信メソッドではなくGETを許可している場合は、問題を解決し、従来の方法に適合することに注意してください。これらのソリューションは、POSTデータが必要/必要であるという前提で提供されています。


8

同じフォームが2回送信されないことを100%保証する唯一の方法は、発行するそれぞれに一意の識別子を埋め込み、サーバーで送信されたものを追跡することです。落とし穴は、ユーザーがフォームのあったページに戻って新しいデータを入力した場合、同じフォームが機能しないことです。


6

答えには2つの部分があります。

  1. 重複した投稿がサーバー側のデータを混乱させないようにしてください。これを行うには、一意の識別子を投稿に埋め込んで、後続のリクエストをサーバー側で拒否できるようにします。このパターンは、メッセージングの用語ではべき等レシーバーと呼ばれます。

  2. 両方が重複して送信する可能性にユーザーが悩まされないようにする

    • POST後のGETへのリダイレクト(POSTリダイレクトGETパターン)
    • JavaScriptを使用してボタンを無効にする

2.の下で何もしないことで、重複送信を完全に防ぐことはできません。人々は非常に速くクリックでき、ハッカーはとにかく投稿できます。重複がないことを確実にしたい場合は、常に1.が必要です。


2

POSTデータでページを更新すると、ブラウザは再送信を確認します。GETデータを使用した場合、メッセージは表示されません。送信を保存した後、データのない3番目のページにリダイレクトすることもできます。


2

まあ、私はこのトリックについて誰も言及していませんでした。

リダイレクトがなくても、更新時にフォームの確認を防ぐことができます。

デフォルトでは、フォームコードは次のようになります。

<form method="post" action="test.php">

今、それを <form method="post" action="test.php?nonsense=1">

あなたは魔法を見るでしょう。

ブラウザーがURLでGETメソッド(クエリ文字列)を取得した場合、確認アラートポップアップをトリガーしないためだと思います。


2

あなたはjqueryを使用してこれを行うことができます

<script>
   $(document).ready(function(){
   window.history.replaceState('','',window.location.href)
   });
</script>

これは、ポストバックのために送信後にデータを再度防止する最もエレガントな方法です。

お役に立てれば。


0

PRGパターンは、ページの更新による再送信のみを防止できます。これは100%安全な手段ではありません。

通常、私は再提出を防ぐために以下の措置をとります。

  1. クライアント側-JavaScriptを使用して、フォームの送信をトリガーするボタンの重複クリックを防止します。最初のクリック後にボタンを無効にすることができます。

  2. サーバー側-送信されたパラメーターのハッシュを計算し、そのハッシュをセッションまたはデータベースに保存します。これにより、重複した送信が受信されたときに、重複を検出し、クライアントへの適切な応答を検出できます。ただし、クライアント側でハッシュを生成することができます。

ほとんどの場合、これらの措置は再提出の防止に役立ちます。


0

@Angelinの答えが本当に好きです。しかし、これが実用的でないレガシーコードを処理している場合は、この手法が役立つ場合があります。

ファイルの先頭

// Protect against resubmits
if (empty($_POST))  {
   $_POST['last_pos_sub'] = time();
} else {
     if (isset($_POST['last_pos_sub'])){
        if ($_POST['last_pos_sub'] == $_SESSION['curr_pos_sub']) {
           redirect back to the file so POST data is not preserved
        }
        $_SESSION['curr_pos_sub'] = $_POST['last_pos_sub'];
     }
}

次に、フォームの最後にlast_pos_sub次のように貼り付けます。

<input type="hidden" name="last_pos_sub" value=<?php echo $_POST['last_pos_sub']; ?>>

0

トリスを試してください:

function prevent_multi_submit($excl = "validator") {
    $string = "";
    foreach ($_POST as $key => $val) {
    // this test is to exclude a single variable, f.e. a captcha value
    if ($key != $excl) {
        $string .= $key . $val;
    }
    }
    if (isset($_SESSION['last'])) {
    if ($_SESSION['last'] === md5($string)) {
        return false;
    } else {
        $_SESSION['last'] = md5($string);
        return true;
    }
    } else {
    $_SESSION['last'] = md5($string);
    return true;
    }
}

使用方法/例:

if (isset($_POST)) {
    if ($_POST['field'] != "") { // place here the form validation and other controls
    if (prevent_multi_submit()) { // use the function before you call the database or etc
        mysql_query("INSERT INTO table..."); // or send a mail like...
        mail($mailto, $sub, $body); // etc
    } else {
        echo "The form is already processed";
    }
    } else {
    // your error about invalid fields
    }
}

フォント:https : //www.tutdepot.com/prevent-multiple-form-submission/


0

jsを使用してデータの追加を防止します。

if ( window.history.replaceState ) {
    window.history.replaceState( null, null, window.location.href );
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.