在http模块中检测页面刷新

发布于 2025-01-05 02:32:51 字数 28 浏览 1 评论 0原文

我们如何检测 http 模块中的页面刷新?

How do we detect page refresh in a http module ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

野味少女 2025-01-12 02:32:51

使用代码

<httpModules>
<add name="RefreshDetectionModule" type="HttpModules.RefreshDetectionModule"/>
</httpModules>

页面刷新检测,第一步:

为了将 HTTP-POST 与其他 HTTP-POST 区分开来,我决定坚持注入(或多或少)发送给客户端的每个页面中的唯一 ID。为了实现这一目标,我编写了自己的类,该类继承自 Stream 类,并将其挂接至 Response.Filter。

private void application_PreRequestHandlerExecute(object sender, EventArgs e)
{
   HttpApplication application = (HttpApplication)sender;
   HttpContext context = application.Context;
   //write the hidden field only if the request is made to the aspx-handler
   if(context.Request.Path.ToLower().EndsWith(".aspx"))
   {
     //attach the stream that writes the hidden field
     application.Response.Filter =
       new RefreshDetectionResponseFilter(application.Response.Filter,
       Guid.NewGuid());
   }
}

流类(RefreshDetectionResponseFilter)基本上只需要重写Write-方法。我将整个流写入 StringBuilder 并在生成的 HTML 文本中搜索表单标记。

public override void Write(byte[] buffer, int offset, int count)
{
 //Read the buffer from the stream
 string sBuffer = UTF8Encoding.UTF8.GetString(buffer, offset, count);
 //when the end of the html-text is read
 if (endOfFile.IsMatch(sBuffer))
 {
   //append the buffer
   html.Append(sBuffer);
   //and fire the matching for the start of the form-tag
   //the form tag contains various additional attributes, therefore
   //a non-greedy expression is used to find the whole opening tag.
   MatchCollection aspxPageMatches =
     Regex.Matches(html.ToString(),"<form[^>]*>",RegexOptions.IgnoreCase);
   //When a form-tag could be found
   if(aspxPageMatches.Count > 0)
   {
       StringBuilder newHtml = new StringBuilder();
       int lastIndex = 0;
       //usually only one form tag should be
       //inside a html-text, but who knows ;)
       for(int i = 0; i < aspxPageMatches.Count; i++)
       {
           //Get the text up to the form tag.
           newHtml.Append(html.ToString().Substring(lastIndex,
                          aspxPageMatches[i].Index -lastIndex));
           //get the opening form-tag
           string key = aspxPageMatches[i].Value;
           //generate the new hidden field
           string enc = string.Format("\r\n<input id=\"{0}\" type" +
                  "=\"hidden\" name=\"{0}\"  value=\"{1}\"/>",
                  HIDDEN_FIELD_ID, guid);
           //write both the the html-text
           newHtml.Append(key+enc);
           lastIndex = aspxPageMatches[i].Index +
                       aspxPageMatches[i].Value.Length;
       }
       //append the rest of the html-text
       newHtml.Append(html.ToString().Substring(lastIndex));
       html = newHtml;
   }
   //write the whole text back to the stream
   byte[] data = UTF8Encoding.UTF8.GetBytes(html.ToString());
   responseStream.Write(data, 0, data.Length);
}
else
{
   //when the end of the html-text is not found yet,
   //write the buffer to the stringbuilder only
   html.Append(sBuffer);
}
 }

页面刷新检测,第二步

现在所有页面都包含隐藏字段,我只需要在页面回发后查找隐藏字段的值。为此,我只需连接 HttpModule 的 BeginRequest 事件并在发布的表单中查找隐藏字段。

private void application_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
string s = "";
//Refreshing is only prohibited of the request is a post-request.
if(context.Request.HttpMethod.ToUpper().Equals("POST"))
{
    //Get the guid from the http-post form
    if(context.Request.Form!=null)
        s = context.Request.Form[RefreshDetectionResponseFilter.HIDDEN_FIELD_ID];
    //if the guid is already in the queue the post is a refresh
    if(q.Contains(s) && s.Length>0)
    {
        //refresh -> Redirect to any other page
        context.Response.Redirect("Logout.aspx");
        context.Response.Flush();
        context.Response.End();
    }
    //when the queue-size exceeded its limit (queueSize), guids will be
    //removed from the queue until the queue size is lower than the limit.
    while(q.Count>=queueSize)
        q.Dequeue();
    //since the post is not a refresh the guid is written to the queue
    q.Enqueue(s);
 }
}

希望有帮助

Using the code

<httpModules>
<add name="RefreshDetectionModule" type="HttpModules.RefreshDetectionModule"/>
</httpModules>

Page-refresh Detection, Step One:

To differ an HTTP-POST from another one, I decided to stick with the idea of injecting a (more or less) unique ID in every page that gets sent to the client. To achieve this, I wrote my own class that inherits from the Stream class and hooked it to the Response.Filter.

private void application_PreRequestHandlerExecute(object sender, EventArgs e)
{
   HttpApplication application = (HttpApplication)sender;
   HttpContext context = application.Context;
   //write the hidden field only if the request is made to the aspx-handler
   if(context.Request.Path.ToLower().EndsWith(".aspx"))
   {
     //attach the stream that writes the hidden field
     application.Response.Filter =
       new RefreshDetectionResponseFilter(application.Response.Filter,
       Guid.NewGuid());
   }
}

The stream-class (RefreshDetectionResponseFilter) basically just needs to override the Write-method. I write the whole stream to a StringBuilder and search in the resulting HTML-text for the form tag.

public override void Write(byte[] buffer, int offset, int count)
{
 //Read the buffer from the stream
 string sBuffer = UTF8Encoding.UTF8.GetString(buffer, offset, count);
 //when the end of the html-text is read
 if (endOfFile.IsMatch(sBuffer))
 {
   //append the buffer
   html.Append(sBuffer);
   //and fire the matching for the start of the form-tag
   //the form tag contains various additional attributes, therefore
   //a non-greedy expression is used to find the whole opening tag.
   MatchCollection aspxPageMatches =
     Regex.Matches(html.ToString(),"<form[^>]*>",RegexOptions.IgnoreCase);
   //When a form-tag could be found
   if(aspxPageMatches.Count > 0)
   {
       StringBuilder newHtml = new StringBuilder();
       int lastIndex = 0;
       //usually only one form tag should be
       //inside a html-text, but who knows ;)
       for(int i = 0; i < aspxPageMatches.Count; i++)
       {
           //Get the text up to the form tag.
           newHtml.Append(html.ToString().Substring(lastIndex,
                          aspxPageMatches[i].Index -lastIndex));
           //get the opening form-tag
           string key = aspxPageMatches[i].Value;
           //generate the new hidden field
           string enc = string.Format("\r\n<input id=\"{0}\" type" +
                  "=\"hidden\" name=\"{0}\"  value=\"{1}\"/>",
                  HIDDEN_FIELD_ID, guid);
           //write both the the html-text
           newHtml.Append(key+enc);
           lastIndex = aspxPageMatches[i].Index +
                       aspxPageMatches[i].Value.Length;
       }
       //append the rest of the html-text
       newHtml.Append(html.ToString().Substring(lastIndex));
       html = newHtml;
   }
   //write the whole text back to the stream
   byte[] data = UTF8Encoding.UTF8.GetBytes(html.ToString());
   responseStream.Write(data, 0, data.Length);
}
else
{
   //when the end of the html-text is not found yet,
   //write the buffer to the stringbuilder only
   html.Append(sBuffer);
}
 }

Page-refresh Detection, Step Two

Now that all the pages contain the hidden field, I just need to look out for the value of the hidden field, once the page is posted back. To do so, I just hook up to the BeginRequest-event of the HttpModule and look in the posted form for the hidden field.

private void application_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
string s = "";
//Refreshing is only prohibited of the request is a post-request.
if(context.Request.HttpMethod.ToUpper().Equals("POST"))
{
    //Get the guid from the http-post form
    if(context.Request.Form!=null)
        s = context.Request.Form[RefreshDetectionResponseFilter.HIDDEN_FIELD_ID];
    //if the guid is already in the queue the post is a refresh
    if(q.Contains(s) && s.Length>0)
    {
        //refresh -> Redirect to any other page
        context.Response.Redirect("Logout.aspx");
        context.Response.Flush();
        context.Response.End();
    }
    //when the queue-size exceeded its limit (queueSize), guids will be
    //removed from the queue until the queue size is lower than the limit.
    while(q.Count>=queueSize)
        q.Dequeue();
    //since the post is not a refresh the guid is written to the queue
    q.Enqueue(s);
 }
}

I hope it helps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文