使用浏览器“后退”按钮后,ASP.NET从错误的下拉列表回发
本文关键字:错误 NET 下拉列表 ASP 浏览器 后退 按钮 | 更新日期: 2023-09-27 18:22:21
我有一个ASP.NET 2.0 web应用程序,它部分通过使用DropDownList
控件进行导航。当其中一个更改时,会导致回发,然后根据下拉列表中选择的内容将其重定向到另一个URL。
我注意到在使用下拉菜单后使用浏览器的"后退"按钮时出现了奇怪的行为。程序如下:
- 在其中一个下拉列表中进行选择,导致回发和重定向。到目前为止还不错
- 单击浏览器的"后退"按钮
- 在之前使用的导航下拉列表下方的另一个导航下拉列表中(它们都包含在一个
div
中),进行选择。页面重定向到与第一次相同的URL,而不是根据其他下拉列表重定向到的URL
我在Firefox 10和IE9中都尝试过,看到了同样的东西。我查看了Firebug中的Net选项卡,发现在步骤3的POST中,引用了正确的控件。但当我调试它时,错误下拉列表(步骤1中使用的下拉列表)的事件处理程序会启动。
代码非常简单明了。标记示例:
<asp:DropDownList runat="server" ID="ddlTest" AutoPostBack="true" />
下拉列表实际上并不是简单的<asp:DropDownList ... />
元素;我使用类似的方法插入optgroup
元素。
C#示例:
ddlTest.Click += new EventHandler(ddlTest_SelectedIndexChanged);
并且在ddlTest_SelectedIndexChanged
:中
if (ddlTest.SelectedValue != "")
{
Response.Redirect(MyUtilClass.GetUrl(ddlTest.SelectedValue));
}
这是怎么回事?
2012年6月2日更新:我通过在SelectedIndexChanged
事件处理程序中检查Request["__EVENTTARGET"]
的内容来修复此问题。不过,我仍然很好奇为什么会发生这种事。为什么第一个事件重复?为什么只有当第二次回发发生在第一次回发之下的控件时才会发生?
单击后退按钮后,会显示上次访问的页面,因为它保存在客户端上,不会再次向服务器发送/请求,这包括上次发布的值,如您在单击后退按钮之后选择第二个DropDownlist后显示的值。
IE上的onload方法(有关其他浏览器,请参阅:http://dean.edwards.name/weblog/2005/09/busted/)当你按下第二个页面上的后退按钮时,第一个页面的会被触发,所以使用它,我们可以在重定向页面之前尝试在客户端上保存回发操作,我们用JS将其保存在一个隐藏值上,然后,一旦用户返回,onload方法将评估隐藏的是否有值,如果有,则将页面的位置更改为自身,以便再次请求页面,并清除所有发布的值:
page1.aspx
<script type="text/javascript">
function redir(){
var h=document.getElementById('hdR');
if (h.value=='1'){
h.value='0';
document.location.href='page1.aspx';
}
}
function changeHids(){
var h=document.getElementById('hdR');
h.value='1';
}
</script>
</head>
<body onload="redir();">
<form id="form1" runat="server">
<div>
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="true" onchange="changeHids();">
<asp:ListItem>1</asp:ListItem>
<asp:ListItem>2</asp:ListItem>
<asp:ListItem>3</asp:ListItem>
<asp:ListItem>4</asp:ListItem>
</asp:DropDownList>
<br />
<asp:DropDownList ID="DropDownList2" runat="server" AutoPostBack="true" onchange="changeHids();">
<asp:ListItem>5</asp:ListItem>
<asp:ListItem>6</asp:ListItem>
<asp:ListItem>7</asp:ListItem>
<asp:ListItem>8</asp:ListItem>
</asp:DropDownList>
<asp:HiddenField ID="hdR" runat="server"/>
</div>
</form>
</body>
Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged
Response.Redirect("page2.aspx?ddl=1&val=" & Me.DropDownList1.SelectedValue, True)
End Sub
Protected Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList2.SelectedIndexChanged
Response.Redirect("page2.aspx?ddl=2&val=" & Me.DropDownList2.SelectedValue, True)
End Sub
page2.aspx
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Response.Write("ddl:" & Request.QueryString("ddl") & " " & "value:" & Request.QueryString("val"))
End Sub
Firefox-添加代码隐藏:
protected void Page_Load(object sender, EventArgs e)
{
Response.AppendHeader("Cache-Control", "no-store");
}
Chrome-添加javascript页面加载:
var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
if (is_chrome) {
document.getElementById("form1").reset();
}
您可以使用Response.Cache属性来解决此问题,因为您允许在浏览器内存中缓存列表。来自MSDN SetAllowResponseInBrowserHistory
当HttpCacheability设置为NoCache或ServerAndNoCache时Expires HTTP标头默认设置为-1;这个告诉客户不要在"历史记录"文件夹中缓存响应,以便在使用后退/前进按钮客户端请求新版本的响应每次。您可以通过调用带有allow参数集的SetAllowResponseInBrowserHistory方法真实。
在页面加载方法中,您可以添加此行。
protected void Page_Load(object sender, EventArgs e)
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetAllowResponseInBrowserHistory(false);
// or else you can do like this
Response.ExpiresAbsolute = DateTime.Now.AddDays(-1d);
Response.Expires = -1;
Response.CacheControl = "No-cache";
}
因此,每当您按下返回键时,t每次都会请求一个新版本的响应。
@Ravi的回答略有变化,这对我很有用…
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Context.Response.AddHeader("Cache-Control", "max-age=0,no-cache,no-store");
Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
Context.Response.Cache.SetMaxAge(TimeSpan.Zero);
....
}