`
long546324
  • 浏览: 206658 次
  • 性别: Icon_minigender_1
  • 来自: 云南
社区版块
存档分类
最新评论

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

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


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,

出自http://www.cnblogs.com/xiaobier
分享到:
评论

相关推荐

    如何用Response.Redirect方法传递汉字

    ### 如何用Response.Redirect方法传递汉字 在ASP.NET开发中,使用`Response.Redirect`方法进行页面跳转并传递参数是一种常见的做法。然而,在实际应用中,可能会遇到通过该方法传递包含汉字的参数时出现乱码或字符...

    Response.Redirect与Server.Transfer的区别

    在ASP.NET开发中,页面跳转是常见的操作,主要涉及两种方法:Response.Redirect和Server.Transfer。它们虽然都能实现页面间的导航,但在工作原理、数据处理和用户体验上存在显著差异。 **Response.Redirect** ...

    文件下载response.setHeader()下载中文文件名乱码问题解决办法.pdf

    文件下载response.setHeader()下载中文文件名乱码问题解决办法 本文主要讨论了文件下载时response.setHeader()下载中文文件名乱码问题的解决办法。该问题是由于 HTTP 消息头中的 Content-Disposition 头字段不正确...

    jsp response.sendRedirect不跳转的原因分析及解决.docx

    ### jsp response.sendRedirect不跳转的原因分析及解决 #### 一、问题背景 在进行Web应用开发的过程中,经常需要使用到服务器端重定向的技术。在Java Server Pages (JSP) 技术中,`response.sendRedirect()` 是一...

    Response.Redirect 正在中止线程解决方案

    在ASP.NET开发中,我们经常会遇到“正在中止线程”(ThreadAbortException)的异常,这通常是由于在页面处理过程中使用了`Response.Redirect`或`Response.End`等方法所导致的。这些方法会中断当前线程的执行,引发异常...

    Jsp利用response.sendRedirect、cookie传参

    在上述示例中,不仅通过`response.sendRedirect`实现了页面跳转和参数传递,还通过Cookie机制实现了数据的跨页面持久化存储。`writeCookie.jsp`负责写入Cookie并重定向至`readCookie.jsp`,而`readCookie.jsp`则负责...

    response.setHeader问题

    response.setHeader 问题详解 Response.setHeader 问题是指在 Servlet 中使用 response 对象的 setHeader 方法来设置 HTTP 消息报头,以控制浏览器的缓存行为。本文将详细解释 response.setHeader 的作用、HTTP ...

    python使用response.read()接收json数据的实例

    以上这篇python使用response.read()接收json数据的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持软件开发网。 您可能感兴趣的文章:Python简单读取json文件功能示例Python使用内置...

    Request和Response.txt

    使用`Response.Write`方法可以在页面上输出内容。这对于动态生成HTML内容非常有用。 ```vbnet Response.Write("&lt;h1&gt;Hello World!&lt;/h1&gt;") ``` ##### 3.2 结束当前响应 在某些情况下,可能需要立即终止当前的响应...

    三种方法让Response.Redirect在新窗口打开

    标题中提到的“三种方法让Response.Redirect在新窗口打开”,涉及到的技术点是基于***的网页编程。***是微软推出的一个用于构建Web应用程序的框架。Response.Redirect是一个在***中常用的服务器端方法,用于将用户从...

    response.getWriter().write()用于ajax

    在IT行业中,尤其是在Web开发领域,`response.getWriter().write()` 是一个常见的Java Servlet API方法,用于向客户端(通常是浏览器)发送响应数据。这个方法在处理AJAX(Asynchronous JavaScript and XML)请求时...

    高效的使用 Response.Redirect解决一些不必要的问题

    通过endResponse = false 在Response.Redirect将会解决这个问题. 但这样做会导致应用程序出现一些奇怪的问题。因为应用程序将假设在 Response.Redirect 将在当前页面停止执行.除此之外你需要处理一些安全隐患,因为...

    C#中Response.Write常见问题汇总

    在使用Ajax的`UpdatePanel`时,由于`UpdatePanel`的无刷新特性,直接使用`Response.Redirect`或`Response.Write`进行页面重定向会导致错误。这是因为`Response.Redirect`需要完整页面刷新才能执行。为了解决这个问题...

    Response.AppendHeader使用大全

    ### Response.AppendHeader 使用大全 #### 一、概述 在 Web 开发中,`Response.AppendHeader` 方法被广泛用于向 HTTP 响应头添加自定义头部信息。这些头部信息可以用来控制浏览器的行为,如缓存策略、文件下载方式...

    response redirect 新窗口大开网页

    ### Response.Redirect 与新窗口打开网页的技术解析 在Web开发中,经常需要处理页面重定向以及在新窗口中打开链接的需求。本文将详细介绍如何利用ASP.NET中的`Response.Redirect`方法结合客户端脚本技术来实现这一...

    ASP.NET Core自定义中间件如何读取Request.Body与Response.Body的内容详解

    为了解决这个问题,我们可以在读取内容后,将原始的`Stream`备份,然后恢复回去,以便后续的中间件能够正常工作。 ```csharp public async Task InvokeAsync(HttpContext context) { // 备份Request.Body var ...

    服务器提交了协议冲突. Section=ResponseStatusLine解决方法

    ### 服务器提交了协议冲突.Section=ResponseStatusLine 解决方法 #### 背景与问题描述 在使用 C# 的 `HttpWebRequest` 类进行 HTTP 请求(包括 POST 和 GET 方法)时,有时会遇到“服务器提交了协议冲突. Section=...

    JSP_重复提交_解决方法

    在Web应用程序开发中,尤其是在使用Java Server Pages (JSP)技术时,一个常见的问题是重复提交数据。当用户不小心刷新了页面或按下了浏览器的“后退”按钮时,可能会导致同一份数据被提交多次,从而对数据库造成不必...

Global site tag (gtag.js) - Google Analytics