在ASP.NET MVC中有什么替代方法可以进行POST-redirect-GET?

时间:2009-08-16 16:32:41

标签: asp.net-mvc usability

通过post提交表单,然后重定向到相同或不同的URL的ASP.NET MVC模式非常容易编码。

想象一下这种情况:

  1. 用户转到 / products / 42 / edit 查看和修改产品42。
  2. 他们在该页面上看到了疯狂的东西,编辑了它,然后点击了保存。这会导致POST / products / 42 / edit
  3. 操作会更新数据并重定向到会返回 / products / 42 / edit
  4. 的视图
  5. 用户会看到更新后的数据并感到满意。
  6. 一小时后,他们点击刷新以查看是否有其他人弄乱了产品#42。
  7. 由于 / products / 42 / edit 的上次检索是POST,因此他们的浏览器会要求重新提交表单数据。这很烦人很危险,因为它可以覆盖别人的数据。
  8. 我担心,即使我为POST和GET使用两个不同的URL(例如 / products / 42 / edit / products / 42 ),浏览器也是如此仍然会要求重新发布,并可以销毁数据。我错了吗?

    可以使用哪些替代方法,以便在提交产品更改后,用户可以安全地点击刷新以获取更新的视图?

    更新我现在看到我的问题和我的设计混乱,我为此道歉。我发现在POST和GET之间共享URL(操作)对我来说是一个坏主意。我是否正确地假设,如果这两者不同,那么我将不会有“刷新导致rePOST”的问题?

6 个答案:

答案 0 :(得分:8)

虽然我同意在帖子完成后不再将用户返回编辑视图的主要答案中所说的内容;它没有回答为什么推送刷新重新发布表单的问题。

以下是“在浏览器中刷新导致另一个帖子”问题的解决方案。

目前你正在这样做:

[AcceptVerbs(HttpVerbs.Post)]    // <--  this action will be used for POSTs
EditProduct(string data1, string data2) 
{
    // Handle Data, save to DB
    // Do some work
    return View("EditProduct");  //  <-- You are rendering the view from
}                                //      A post action - this is bad!  

事实上你应该这样做:


[AcceptVerbs(HttpVerbs.Post)]    //  <-- This action will be used for POSTs
EditProduct(string data1, string data2) 
{
    // Handle Data, save to DB
    // Do some work
    return RedirectToAction("EditProduct"); // <-- Redirect to a GET Action
}

[AcceptVerbs(HttpVerbs.Get)]   //  <-- This action will be used for GETs
EditProduct() 
{

    return View("EditProduct"); // <-- Render the view from the GET action
}                               //     So when you refresh it will refresh the GET

关键是,不要返回View以响应POST,否则浏览器中的最后一个请求是POST请求,并且浏览器中的推送刷新将重新发布。相反,当您完成后期操作后,使用RedirectToAction()重定向到“GET”操作。 GET操作又返回View。这意味着浏览器中的先前请求是GET请求,如果您按下刷新它将再次获取它,而不是重新发布它。当我开始使用MVC时,我犯了同样的错误。

答案 1 :(得分:5)

更新时间:是。

使用/ product / {id} /进行查看,使用/ product / {id} / edit进行编辑,然后在编辑后将其重定向到/ product / {id} /。

问题解决了。想知道你为什么/正在使用/ product / {id} / edit进行查看和编辑。

答案 2 :(得分:1)

如果确实想要查看和编辑相同的页面并且您需要处理并发,则可以包含保留上次更新日期的隐藏字段。所以流程将是:

  1. User1提交数据。
  2. 使用日期元素(比如说date1)渲染同一页面。
  3. User2提交此页面。
  4. User1再次提交。该操作会比较date1和实际更新日期。
  5. 在不同情况下,它们不同,因此操作不应更新并告知用户。
  6. 这只是另一种选择。

答案 3 :(得分:0)

答案 4 :(得分:0)

您说当用户点击刷新时,您会看到过时的视图。由此我假设您的GET操作正在使用POST操作中存储在TempData内的一些对象。在这种情况下,可能的解决方法是使用Session而不是TempData来存储POST操作的结果。

答案 5 :(得分:0)

为了使您的发布表单以您描述的方式工作,它需要从数据库中读取数据并预填充表单上的字段。它需要在您第一次输入相关URL时执行此操作。

然后,当您发布时,它需要在验证后将值保存到数据库。这将完成您的往返循环。

如果页面是空白的“新记录”页面,那么您是对的,它只会在验证失败时往返一次。在F5上,它只会根据设计为您提供一个新的空白表格。