为什么不实现'IsRefresh','IsBackPost'就像是'IsPostBack'?

时间:2010-02-16 08:05:31

标签: asp.net refresh

我可以看到,我自己和很多人在ASP.NET中使用这两个项目时遇到了麻烦...刷新按钮,后退按钮......(我看到很多人都去问过如何禁用这两个按钮在浏览器..)

现在在Page中实现两个更多的布尔变量有什么问题(IsRefresh,IsPostBack)......如果这些问题可以被规避和实施,那对开发者来说将是一笔巨大的资产......

当您回答时,如果您还可以在Web应用程序中包含您要采取的步骤,以避免在有用的情况下重新发布(有时在数据库中)。

由于

3 个答案:

答案 0 :(得分:5)

实现两个额外的布尔属性的问题是,确实没有(可靠的)方法来区分 Back / Refresh 触发的请求。当点击这些按钮时,浏览器将:

  1. 如果允许,则显示缓存中的页面,或
  2. 再次执行完全相同的请求(可能要求用户先确认)
  3. 您正在遇到案例#2。发生第二个请求时,服务器将收到与原始请求相同的完全相同的请求数据。因此,ASP.NET(和大多数其他框架)将处理请求,就像处理原始请求一样。有几种方法可以解决此问题:

    1. 更改您的缓存策略,以允许浏览器重新显示先前请求的结果(可能会解决 Back 问题,但不能解决 Refresh )。
    2. 在预期回发的页面上添加一个包含唯一值的隐藏字段(或ViewState中的数据)。然后添加一些数据结构以保留“已使用”值的列表,以及在执行任何关键操作之前测试重复项的逻辑。
    3. 使用Post/Redirect/Get pattern确保POST请求永远不会在浏览器历史记录中结束。
    4. 解决方案#3简单易行,几乎适用于所有情况。基本上,而不是将结果/确认作为对“关键”回发的回复返回,请重定向到新的URL:

      protected void btnCritical_Click(object sender, EventArgs e)
      {
          DoSomethingThatShouldNotBeDoneTwice();
          Response.Redirect("confirmation.aspx");
      }
      

答案 1 :(得分:1)

这不是那么明确。服务器识别“PostBack”的唯一方法是基于请求传递给页面的标头。当您发布表单时,“IsPostBack”是正确的,正如您所期望的那样。刷新页面或按“返回”时,将发送完全相同的请求数据。应用程序无法检测用户是否发出了非标准请求(后退或刷新)而未更改发送请求的浏览器的行为。

如您所知,大多数浏览器会向您显示“单击后退将重新发送表单数据...”,但这仅仅是浏览器发出的警告,让您知道它将发送完全相同的请求再次。服务器不知道这一点,也没有(本地)方式来解释信息。

双重预回复提示

阻止数据发布两次的一种方法是确保每个PostBack都包含一些您可以验证的唯一数据。这个过程相当简单。

在每个页面加载时,您将需要为该页面的PostBack事件创建唯一标识符。唯一ID是什么并不重要,只要它在顺序页面加载时不一样。将该唯一标识符放在页面上的隐藏字段中以及用户的会话(或cookie)中。然后,在每个PostBack上验证隐藏字段中的cookie 是否匹配会话中的值。如果值匹配,则PostBack是页面的原始帖子,可以相应地进行处理。执行必要的操作后,您需要再次更改两个位置中的唯一标识符。这样,如果用户应该回击并选择“重新发送数据”,则隐藏字段将与会话密钥不匹配,您可以丢弃重复的发布数据。

答案 2 :(得分:1)

aspnet_isapi识别来自表单内容的回发,特别是ViewState字段。它没有内在的方法来区分回发和刷新。

过去,我已经看到了一些与此相关的策略。一种方法是为每个请求分配一个guid,并将其用作您写入的表中的唯一键或索引。

您可以创建所有网页都继承的基页。

public partial class PageBase : System.Web.UI.Page
{
    private Guid _requestId;

    protected Guid RequestId
    {
        get
        {
            return _requestId;
        }   
    }
    protected virtual void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            _requestId = Guid.NewGuid();
            ViewState.Add("requestId", _requestId);
        }
        else
        {
            _requestId = (Guid)ViewState["requestId"];
        }
    }
}

public partial class _Default : PageBase
{
    protected override void Page_Load(object sender, EventArgs e)
    {
        base.Page_Load(sender, e);

        // now do stuff
    }
}