【问题标题】:What alternative is there to POST-redirect-GET in ASP.NET MVC?ASP.NET MVC 中的 POST-redirect-GET 有什么替代方法?
【发布时间】:2009-08-16 16:32:40
【问题描述】:

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

想象一下这个场景:

  1. 用户转到 /products/42/edit 以查看和编辑产品 42。
  2. 他们在该页面上看到一些疯狂的东西,对其进行编辑,然后点击保存。这会导致发布到 /products/42/edit
  3. 该操作更新数据并重定向到或返回 /products/42/edit 的视图
  4. 用户看到更新的数据并且很高兴。
  5. 一小时后,他们单击刷新以查看是否有其他人弄乱了产品 #42。
  6. 由于 /products/42/edit 的最后一次检索是 POST,因此他们的浏览器要求重新提交表单数据。这很烦人并且很危险,因为它可能会覆盖其他人的数据。

我担心即使我为 POST 和 GET 使用两个不同的 URL(比如 /products/42/edit 和 /products/42),浏览器仍会要求重新发布并可能破坏数据。我弄错了吗?

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

更新我现在看到我的问题和我的设计很混乱,对此我深表歉意。我发现在 POST 和 GET 之间共享 URL(操作)对我来说是个坏主意。我是否可以假设如果这两者不同,那么我就不会有“刷新导致重新发布”的问题?

【问题讨论】:

  • 我不明白这个问题。用户提交他们的编辑,这些被写入数据库,然后用户被引导到产品的当前视图。他们点击 F5 和产品更新的当前视图。问题出在哪里?
  • 考虑在你的控制器方法和视图中发布一些代码,这样我们就可以看到发生了什么。
  • 我已经澄清了这个问题(我希望如此)。我发现在 POST 和 GET 之间共享 URL 对我来说是个坏主意。我是否可以假设如果这两者不同,那么我就不会有“刷新导致重新发布”问题?

标签: asp.net-mvc usability


【解决方案1】:

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

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

目前你正在这样做:

[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

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

【讨论】:

  • POST 成功后重定向到 GET 总是一个好主意。但如果 ModelState 无效,只需调用 GET EditProduct 方法即可。调用 EditProduct 方法将重建视图,MVC 框架将使用来自 ModelState 的发布值覆盖任何模型数据。
  • 真的很好解释...恭喜! :)
【解决方案2】:

您的更新:是的。

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

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

【讨论】:

  • 附录:如果你真的想在同一个页面中查看和编辑,那么你应该考虑 ajaxify 你的表单。
【解决方案3】:

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

  1. User1 提交数据。
  2. 呈现相同的页面,但使用日期元素(比如说 date1)。
  3. User2 提交此页面。
  4. User1 再次提交。该操作将 date1 与实际更新日期进行比较。
  5. 如果它们不同,则操作不应更新并告知用户。

这只是另一种选择。

【讨论】:

  • 版本号会比日期好
【解决方案4】:

【讨论】:

  • 当用户按 F5 时,AJAX 化表单将无济于事。
  • 这取决于您的表单是否足够聪明,可以弄清楚当前状态,不是吗?
  • 但是如果表单足够聪明,可以计算出当前状态,它也可以在没有 AJAX 的情况下工作。我认为 Frank Krueger 的一些示例代码会让事情变得更清楚。
【解决方案5】:

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

【讨论】:

    【解决方案6】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-04
      • 1970-01-01
      • 1970-01-01
      • 2011-01-06
      相关资源
      最近更新 更多