13

私は購入ページを持っていますが、ユーザーが「注文完了」ページに到達したときにページを更新してフォームを再送信できないようにしたくありません。 Paypal 経由 (これらは 1 回だけ発生させたい) ... 「更新を押さないでください。2 回請求されます!」と言うサイトを見たことがあります。しかし、それを可能性に開いたままにしておくのはかなり不自由です。一度だけ送信できるようにしたり、更新を防止したりする良い方法は何ですか?

PS: 私はいくつかの同様の質問を見ました: PHP: フォームが誤って再処理されるを防ぎます。しかし、満足のいく答えが見つかりませんでした...これに対するメカニズムがあれば、ASP.NET MVC固有の答えも理想的です。

編集:彼らがクリックしてコントローラーに投稿すると、コントローラーはいくつかの魔法を実行し、注文完了メッセージを含むビューを返しますが、ブラウザーで更新をクリックすると、「このフォームを再送信しますか?」 ' それは悪い...

4

9 に答える 9

21

これに対する標準的な解決策は、POST/REDIRECT/GETパターンです。このパターンは、ほぼすべての Web 開発プラットフォームを使用して実装できます。通常は次のようにします。

  • POST 後に送信を検証する
  • 失敗した場合は、検証エラーが表示された元のエントリ フォームを再レンダリングします
  • 成功した場合は、確認ページ、または入力を再表示するページにリダイレクトします - これは GET 部分です
  • 最後のアクションは GET だったので、ユーザーがこの時点で更新した場合、フォームの再送信は発生しません。
于 2010-01-21T19:37:27.960 に答える
17

私は RedFilter の一般的な回答に 100% 同意しますが、特に ASP.NET MVC に関連するコードをいくつか投稿したかったのです。

Post/Redirect/Get (PRG) パターンを使用して、二重ポストバックの問題を解決できます。

この問題を図で示します。

ダイアグラム

ユーザーが更新を押すと、ブラウザは最後に行ったリクエストを再送信しようとします。最後のリクエストが投稿だった場合、ブラウザはそれを試みます。

ほとんどのブラウザーは、これが通常ユーザーが望んでいることではないことを認識しているため、自動的に次のように尋ねます。

Chrome - 入力した情報を探しているページ。そのページに戻ると、実行したアクションが繰り返される可能性があります。続けたいですか?
Firefox - このページを表示するために、Firefox は以前に実行されたアクション (検索や注文の確認など) を繰り返す情報を送信する必要があります。
Safari - もう一度フォームを送信してもよろしいですか? このページを再度開くには、Safari がフォームを再送信する必要があります。これにより、重複した購入、コメント、またはその他のアクションが発生する可能性があります。
インターネットエクスプローラ- Web ページを再度表示するには、以前に送信した情報を Web ブラウザーが再送信する必要があります。購入を行っていた場合は、取引の重複を避けるために [キャンセル] をクリックしてください。それ以外の場合は、[再試行] をクリックして Web ページを再度表示します。

しかし、PRG パターンは、クライアントにリダイレクト メッセージを送信することで、これを完全に回避するのに役立ちます。そのため、ページが最終的に表示されたときに、ブラウザが最後に実行した要求は、新しいリソースに対する GET 要求でした。

これは、MVC のパターンの実装を提供するPRG に関する優れた記事です。サーバー上で非べき等アクションが実行された場合にのみ、リダイレクトに頼る必要があることに注意することが重要です。つまり、有効なモデルがあり、実際に何らかの方法でデータを保持している場合は、リクエストが誤って 2 回送信されないようにすることが重要です。ただし、モデルが無効な場合は、現在のページとモデルを返して、ユーザーが必要な変更を加えることができるようにする必要があります。

コントローラーの例を次に示します。

[HttpGet]
public ActionResult Edit(int id) {
    var model = new EditModel();
    //...
    return View(model);
}

[HttpPost]
public ActionResult Edit(EditModel model) {
    if (ModelState.IsValid) {
        product = repository.SaveOrUpdate(model);
        return RedirectToAction("Details", new { id = product.Id });
    }
    return View(model);
}

[HttpGet]
public ActionResult Details(int id) {
    var model = new DetailModel();
    //...
    return View(model);
}
于 2015-02-09T20:11:00.873 に答える
2

注文確認ページを提供している間、DB/キャッシュにも保存するトークンを設定できます。注文確認の最初のインスタンスで、このトークンの存在を確認し、トークンをクリアします。スレッド セーフで実装されている場合、注文を 2 回送信することはできません。

これは、可能な多くのアプローチの 1 つにすぎません。

于 2010-01-21T19:35:22.467 に答える
1

ページが最初に読み込まれたときに、各訪問者のフォームに一意の ID を付与します。フォームが送信されたときに ID をメモします。その ID でフォームが送信されたら、それを使用したそれ以上のリクエストを許可しないでください。更新をクリックすると、同じ ID が送信されます。

于 2010-01-21T19:35:34.910 に答える
0

厄介なことをすべて行うページから「ご注文ありがとうございます」ページにリダイレクトするだけです。これを行うと、ユーザーは好きなだけ更新を押すことができます。

于 2010-01-21T19:37:50.307 に答える
-1

Kazi Manzur Ra​​shidはこれについて書いています(他のasp.net mvcのベストプラクティスと一緒に)。彼は、TempDataを使用してPOSTと次のGETの間のデータ転送を処理するために2つのフィルターを使用することを提案しています。

于 2010-01-22T13:38:02.410 に答える
-1

思いつきで、ページの GET リクエストの非表示フィールドに を生成し、System.Guidそれをチェックアウト/支払いに関連付けます。それを確認して、「支払いは既に処理されました」というメッセージを表示するだけです。など。

于 2010-01-21T19:36:23.193 に答える