您的位置:首页 > 其它

彻底解决刷新重复提交问题,你还在用Response.Redirect吗?

2008-10-31 16:55 489 查看

作者:小比尔 来源:博客园 时间:2008-10-27 阅读:61 次 原文链接 [收藏]

以前也研究过,始终没找到好的办法,看了微软Msdn上的解决方案,使用后发现存在较多漏洞,考虑的情况太少,如页面加载后没有提交,始终刷新,在同一浏览器打开多个各选项卡,每个选项卡打开同一页面或不同页面,以下是我的解决方案,

Code

public class RefreshServe : System.Web.UI.Page

{

private static ILog log = LogManager.GetLogger(typeof(RefreshServe));

private readonly string REFRESH_TICKET_NAME = "__RefreshTicketArray";

private readonly string HIDDEN_FIELD_NAME = "__RefreshHiddenField";

private readonly string HIDDEN_PAGE_GUID = "__RefreshPageGuid";

/// <summary>

/// 为True表示页面刷新,False为正常提交

/// </summary>

public bool IsPageRefreshed

{

get

{

if (IsPostBack && !CheckRefreshFlag())

{

log.Debug("刷新了页面");

return true;

}

else

{

log.Debug("正常提交");

return false;

}

}

}

/// <summary>

/// 呈现前更新标识

/// </summary>

/// <param name="e"></param>

protected override void OnPreRender(EventArgs e)

{

log.Debug("执行OnPreRender");

base.OnPreRender(e);

UpdateRefreshFlag();

}

/// <summary>

/// 更新标识,正常提交都删除该次提交的时间,并生产当前新的时间

/// </summary>

private void UpdateRefreshFlag()

{

#region Cookie模式

//注册页面唯一标识并返回

string pageGuid = SetCurPageGuid();

HttpCookie cookie = GetRefreshTicket();

if (cookie.Values.Count > 0)

{

cookie.Values.Remove(pageGuid);

log.Debug("当前清除的cookie变是:" + pageGuid);

}

string submitTime = DateTime.Now.ToString("hhmmss.fffff");

//当前提交时间保存到隐藏域

ClientScript.RegisterHiddenField(HIDDEN_FIELD_NAME, submitTime);

log.Debug("即将要新增的时间:submitTime:" + submitTime + " Guid:" + pageGuid.ToString());

cookie.Values.Add(pageGuid, submitTime);

log.Debug("UpdateRefreshFlag中当前Cookie中存在的记录数为:" + cookie.Values.Count);

for (int i = 0; i < cookie.Values.Count; i++)

log.Info("cookie[" + cookie.Values.GetKey(i) + "]:" + cookie.Values[i]);

Response.AppendCookie(cookie);

#endregion

}

/// <summary>

/// 验证是否刷新

/// </summary>

/// <returns></returns>

private bool CheckRefreshFlag()

{

HttpCookie cookie = GetRefreshTicket();

string pageGuid = GetCurPageGuid();

if (cookie.Values.Count > 0)

{

bool flag;

if (cookie.Values[pageGuid] != null)

flag = cookie.Values[pageGuid].IndexOf(GetCurSubmitTime()) > -1;

else

flag = true;//防止出现异常,总是可以提交

if (flag)

log.Debug("提交时间存在,可以提交");

else

log.Debug("无效的提交时间");

return flag;

}

return true;

}

/// <summary>

/// 得到已保存的提交时间,没有新建,有返回

/// </summary>

/// <returns></returns>

private HttpCookie GetRefreshTicket()

{

#region Cookie模式,返回值为Cookie

HttpCookie cookie;

if (Request.Cookies[REFRESH_TICKET_NAME] == null)

{

cookie = new HttpCookie(REFRESH_TICKET_NAME);

Response.AppendCookie(cookie);

log.Debug("Cookie不存在,初始化");

}

else

{

cookie = Request.Cookies[REFRESH_TICKET_NAME];

log.Debug("读取已存在的Cookie,当前Cookie中存在的记录数为:" + cookie.Values.Count + "具体有如下几条:");

for (int i = 0; i < cookie.Values.Count; i++)

log.Info("cookie[" + cookie.Values.GetKey(i) + "]:" + cookie.Values[i]);

}

return cookie;

#endregion

}

/// <summary>

/// 获取当前提交时间

/// </summary>

/// <returns></returns>

private string GetCurSubmitTime()

{

string submitTime = Request.Params[HIDDEN_FIELD_NAME] == null ? "" : Request.Params[HIDDEN_FIELD_NAME].ToString();

log.Debug("执行GetCurSubmitTime:submitTime为:" + submitTime);

return submitTime;

}

/// <summary>

/// 设置页面唯一标识,通过Guid标识来区分每个页面自己的提交时间

/// </summary>

private string SetCurPageGuid()

{

string guid;

if (!IsPostBack)

{

if (Request.Params[HIDDEN_PAGE_GUID] == null)

{

guid = System.Guid.NewGuid().ToString();

log.Debug("SetCurPageGuid注册了一个新的标识:" + guid);

}

else

guid = GetCurPageGuid();

}

else

{

guid = GetCurPageGuid();

}

ClientScript.RegisterHiddenField(HIDDEN_PAGE_GUID, guid);

return guid;

}

/// <summary>

/// 得到当前页面的唯一标识

/// </summary>

/// <returns></returns>

private string GetCurPageGuid()

{

string pageGuid = Request.Params[HIDDEN_PAGE_GUID] == null ? "none" : Request.Params[HIDDEN_PAGE_GUID].ToString();

log.Debug("执行GetCurPageGuid()后Page_GUID为:" + pageGuid);

return pageGuid;

}

}

需要刷新判断功能时新页面只需继承该类就可,通过引用属性IsPageRefreshed识别"为真表示刷新,假则是正常提交",将数据库的操作写在

if(!IsPageRefreshed)

{

数据库操作

}

即可,如果是刷新不会执行,代码中注释部分使用的是Session方式保存票证,因为session比较容易丢失且占内存,所以使用cookie,
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: