Prevent double form submissions

2019-01-26 11:59发布

问题:

I have an ASP.NET MVC 3 application which has a post action called Create:

[HttpPost]
public virtual ActionResult Create(Issues issues)
{
    if (ModelState.IsValid)
    {
        context.Issues.Add(issues);
        context.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(issues);
}

If I double click on the submit button by mistake, it'll Create 2x issues. Is there a way of preventing this, without the use of javascript and disabling the button, I thought the whole use of using a RedirectToAction was to prevent this, by using the Post/Redirect/Get design pattern?

回答1:

The pattern you mentioned (Post/Redirect/Get design pattern) prevents page refreshes from double posting because the last action is a GET, not the POST.

If you want to prevent double clicks from double posting, you could:

1. Disable the button after click
2. Maintain a unique index on 'Issues' and look for duplicates
3. Maintain something in session that gives you an indication of a double post

And there maybe a few more ways... I think disabling the button is probably the easiest because you're redirecting to another page anyway.



回答2:

Easy solution!

Disable the submit button when it's clicked. The End.

$('submitButtonId').click(function(){
    $(this).prop('disabled', true);
    $(this).attr('disabled', 'disabled'); // for jQuery versions < 1.6.
});


回答3:

Most simple way I can think of is use the Session:

if (ModelState.IsValid)
{
    DateTime now = DateTime.Now;
    if (Session["LastAdd"] == null || (now - (DateTime)Session["LastAdd"]).TotalMilliseconds > 1000)
    {
        //first time, or more than a second passed since last addition
        context.Issues.Add(issues);
        context.SaveChanges();
        Session["LastAdd"] = now;
    }
    return RedirectToAction("Index");
}


回答4:

You can generate an IssueId when you show the form to the user, then check that you don't already have an issue with such id in your Create method and, for example, skip such requests.



回答5:

The PRG pattern will not prevent this, as the P action in it takes time (which is usually the case) and the user can submit the form again (via click or browser refresh), which will cause the PRG pattern to "fail".

Note that malicious users can also bypass all of your client side measures by running multiple http posts in quick succession.

A solution to all of the above is to check for duplicate submissions on server side using the following method, as described by myself, here.

For your convenience, I quote:

"If you make use of a hidden anti-forgery token in your form (as you should), you can cache the anti-forgery token on first submit and remove the token from cache if required, or expire the cached entry after set amount of time.

You will then be able to check with each request against the cache whether the specific form has been submitted and reject it if it has."