2012年1月1日星期日

用 Ext.Net 程序演示 IE 的 F5/Ctl

本文内容

  • 概述
  • 测试用例
  • 用 HttpWatch 演示几种刷新界面的区别
  • 参考资料

 

概述

当我们初次访问一个页面后,刷新该页面的方式有很多,包括 F5、Ctl-R、Ctl-F5 和 直接在地址栏按回车(如下图所示)。这几个方式是不同的。

 

测试用例

本文测试用例使用 Ext.Net_在程序集中自定义 TreePanel 控件 中的演示。

 

用 HttpWatch 演示几种刷新界面的区别

为保证测试准确性,先用 HttpWatch 清除浏览器缓存,如图1所示:

用 HttpWatch 清除浏览器缓存

图1 用 HttpWatch 清除浏览器缓存

初次访问 Default.aspx 页面后,分别以四种方式请求该页面,结果如下所示:

图2 用四种方式请求 Default.aspx 页面——初次请求、F5、Ctl-R、Ctl-F5、地址栏回车

图2 用四种方式请求 Default.aspx 页面——初次请求、F5、Ctl-R、Ctl-F5、地址栏回车

从上到下分别是:

  • 初次访问
  • F5、
  • Ctl-R、
  • Ctl-F5
  • 直接在地址栏按回车

说明:

  • “初次访问”时,HTTP 状态码返回 200;
  • 用 F5  和 Ctl-R 刷新界面时,页面资源 HTTP 状态码返回 200;除了 tip-sprite.gif 是从缓存获得外,其他资源的 HTTP 状态码均返回 304。F5  和 Ctl-R 刷新界面相同;
  • 用 Ctl-F5 刷新界面时,除了 tip-sprite.gif 是从缓存获得外,所有资源的 HTTP 状态码都返回 200;
  • 直接在地址栏按回车时,所有资源都是从缓存获得的。

下面将分别说明,尤其是你会注意到一些细节,比如,图像 tip-sprite.gif,还有有些图像资源,无论你采用哪种方式刷新,都不会向服务器请求等等,这些细节对在开发 Web 应用程序中,提高其性能很有帮助。

 
初次访问

先看下“初次访问”页面的情况,如下图所示:

图3 初次访问

图3 初次访问

说明:

  • 红色垂直线表示 Page Load 阶段,主要获得了 Ext.Net 嵌入资源的脚本和 CSS 文件,以及在程序集中自定义的一个脚本 myTreePanel.js。
  • 绿色垂直线表示 Render Start 阶段,在Page Load 基础上,就可以呈现页面了。
  • 灰色垂直线表示 HTTP Load 阶段,在Render Start 阶段,页面呈现时,以“渐进增强”的方式,向服务器请求资源,在该演示中主要是图像。例如,请求了按钮图片,不能拖拽的图片,还有树形结构的文件夹和箭头图标等。

参考博文 "以 Ext.Net 为例了解网页测试工具 HttpWatch"。

 

按 F5

图4 初次访问后按 F5

图4 初次访问后按 F5

说明:

  • 重新请求了 Default.aspx 页面,但页面中的其他资源没有,只是返回了 HTTP 状态码 304,告诉客户端请求的资源的没有被修改。而且客户端接收的字节数,与初次访问相比,小得可怜,才 226 bytes。
  • 图像 tip-sprite.gif 是从缓存获得的。

 

按 Ctl-R

图5 初次访问后按 Ctl-R

图5 初次访问后按 Ctl-R

说明:

  • 与 F5 效果和执行的操作的一样。
  • 重新请求 Default.aspx 页面。页面中的其他资源没有,只是返回了 HTTP 状态码 304,而且客户端接收的字节数也是 226 bytes。图像 tip-sprite.gif 也是从缓存获得。

如果你看下 Ext.Net.ResourceHandler 类的 ProcessRequest 方法,代码如下:

public override void ProcessRequest(HttpContext context)
{
    this.context = context;
    
    string file = this.context.Request.RawUrl;
 
    bool isInitScript = file.Contains("extnet/extnet-init-js/ext.axd?");
 
    if (!ResourceHandler.IsSourceModified(context.Request) && !isInitScript)
    {
        context.Response.SuppressContent = true;
        context.Response.StatusCode = 304;
        context.Response.StatusDescription = "Not Modified";
        context.Response.AddHeader("Content-Length", "0");
        return;
    }
    
     ……
    }
}

当客户端再次请求资源时,Ext.Net 会判断自己的相关嵌入资源(即 !ResourceHandler.IsSourceModified(context.Request) && !isInitScript,不是用户自定义脚本且没有被修改)是否被修改,如果没有被修改,就直接返回给客户端 304。下面代码是 Ext.Net 如何判断自己的资源是否被修改:

private static bool IsSourceModified(HttpRequest request)
{
    bool dateModified = false;
 
    string requestIfModifiedSinceHeader = request.Headers["If-Modified-Since"] ?? string.Empty;
    DateTime requestIfModifiedSince;
    DateTime.TryParse(requestIfModifiedSinceHeader, out requestIfModifiedSince);
 
    DateTime responseLastModified = new DateTime(ResourceHandler.GetAssemblyTime(typeof(ResourceHandler).Assembly)).ToUniversalTime();
 
    if (requestIfModifiedSince != DateTime.MinValue && responseLastModified != DateTime.MinValue)
    {
        requestIfModifiedSince = requestIfModifiedSince.ToUniversalTime();
 
        if (responseLastModified > requestIfModifiedSince)
        {
            TimeSpan diff = responseLastModified - requestIfModifiedSince;
            if (diff > TimeSpan.FromSeconds(1))
            {
                dateModified = true;
            }
        }
    }
    else
    {
        dateModified = true;
    }           
 
    return dateModified;
}

从代码中看出,requestIfModifiedSince 是客户端中资源的最后修改时间,responseLastModified 是服务器端中程序集嵌入资源的最后修改时间。当 responseLastModified > requestIfModifiedSince,且 responseLastModified – requestIfModifiedSince > TimeSpan.FromSeconds(1) 时,说明服务器端的资源已经被修改,需要重新把该资源发送给客户端。

 

按 Ctl-F5

图6 初次访问后按 Ctl-F5

图6 初次访问后按 Ctl-F5

说明:

  • 除重新请求了 Default.aspx 页面外,还重新请求了页面中的其他资源,就像客户端初次访问一样。
  • 但是,我们知道,本文四种刷新界面的方式是连续进行的。因此,当执行 Ctl-F5 时,浏览器已经有缓存了该页面的相关资源,但是 Ctl-F5 没有使用,而是直接向服务器重新请求。
  • 可是图像 tip-sprite.gif 仍然是从缓存获得的。

 

直接在地址栏按回车

图7 初次访问后在地址栏按回车

图7 初次访问后在地址栏按回车

说明:

无论是 Default.aspx 页面,还页面中的其他资源,都是从缓存中获得的。

备注

  • 这四种刷新方式:F5、Ctl-R、Ctl-F5 和直接在地址栏按回车。当页面被初次访问后,F5 和 Ctl-R 的操作和效果相同,虽然也发送了请求,但是服务器通过对请求脚本和 CSS 文件的 HTTP 头的日期比较,告诉客户端资源没有任何改变,可以直接其缓存中获得;Ctl-F5 不访问缓存,重新请求页面,及其中的资源,包括脚本和 CSS,就像初次访问页面一样;直接在地址栏按回车,不向服务器发送请求,直接从缓存中获得。
  • 但是,既然 Ctl-F5 不访问本地缓存,但是为什么资源 tip-sprite.gif 图像还是从缓存中获得的?F5 和 Ctl-R 也是如此。
  • 不仅如此,与初次访问页面相比,F5、Ctl-R、Ctl-F5 和直接在地址栏按回车发出 HTTP 请求的次数要少一半。这些重新请求的资源主要是 CSS 文件和脚本,而好几个图像都没再请求了。
  • 没再请求的资源应该得益与 HTTP Expire 头。试想,有这样一个资源,它几乎不会被修改。因此,如果设置它“永不过期”的话,那么在初次访问后,这样的资源就不会 HTTP 请求。

 

参考资料

Internet Explorer Keyboard Shortcuts

http://www.updatexp.com/internet-explorer-keyboard-shortcuts.html

http://windows.microsoft.com/en-US/windows7/Internet-Explorer-keyboard-shortcuts

Wikipedia:Bypass your cache http://en.wikipedia.org/wiki/Wikipedia:Bypass_your_cache#cite_note-0

Using Ctrl+F5 in IE 7 http://blog.httpwatch.com/2007/10/19/using-ctrlf5-in-ie-7/


用 Ext.Net 程序演示 IE 的 F5/Ctl

TAG:Ext Net ASP NET Web开发 HttpWatch