2007年5月1日

这几天用域名在免费空间上挂blog的过程中,遇到很多网络方面的问题。无奈我在网络方面的基础比较差,很多东西搞不懂,走了很多弯路。

用百度搜了一些域名解析方面的名词解释,用来收藏学习。

以下为转载:

什么是域名解析?

域名解析就是域名到IP地址的转换过程。IP地址是网路上标识您站点的数字地址,为了简单好记,采用域名来代替ip地址标识站点地址。域名的解析工作由DNS服务器完成。

什么是A记录?

A (Address) 记录是用来指定主机名(或域名)对应的IP地址记录。用户可以将该域名下的网站服务器指向到自己的web server上。同时也可以设置您域名的二级域名。

什么是MX记录?

邮件路由记录,用户可以将该域名下的邮件服务器指向到自己的mail server上,然后即可自行操控所有的邮箱设置。您只需在线填写您服务器的IP地址,即可将您域名下的邮件全部转到您自己设定相应的邮件服务器上。

什么是CNAME记录?

即:别名记录。这种记录允许您将多个名字映射到同一台计算机。通常用于同时提供WWW和MAIL服务的计算机。例如,有一台计算机名为"host.mydomain.com"(A记录)。它同时提供WWW和MAIL服务,为了便于用户访问服务。可以为该计算机设置两个别名(CNAME):WWW和MAIL。 这两个别名的全称就是http://www.mydomain.comhttp://mail.mydomain.com

什么是TTL值?

TTL值全称是"生存时间(Time To Live)",简单的说它表示DNS记录在DNS服务器上缓存时间。要理解TTL值,请先看下面的一个例子:
假设,有这样一个域名myhost.abc.com(其实,这就是一条DNS记录,通常表示在abc.com域中有一台名为myhost的主机)对应IP地址为1.1.1.1,它的TTL为10分钟。这个域名或称这条记录存储在一台名为dns.abc.com的DNS服务器上。
现在有一个用户在浏览器中键入一下地址(又称URL):http://myhost.abc.com 这时会发生什么呢?
该访问者指定的DNS服务器(或是他的ISP,互联网服务商, 动态分配给他的)8.8.8.8就会试图为他解释myhost.abc.com,当然8.8.8.8这台DNS服务器由于没有包含 myhost.abc.com这条信息,因此无法立即解析,但是通过全球DNS的递归查询后,最终定位到dns.abc.com这台DNS服务器, dns.abc.com这台DNS服务器将myhost.abc.com对应的IP地址1.1.1.1告诉8.8.8.8这台DNS服务器,然有再由 8.8.8.8告诉用户结果。8.8.8.8为了以后加快对myhost.abc.com这条记录的解析,就将刚才的1.1.1.1结果保留一段时间,这就是TTL时间,在这段时间内如果用户又有对myhost.abc.com这条记录的解析请求,它就直接告诉用户1.1.1.1,当TTL到期则又会重复上面的过程。

posted @ 7:44 | Feedback (0)

今天新买的域名把我郁闷了……本来我是把myjojo.com.cn URL转向到我的blog地址,然后隐藏目标地址,但是隐藏目标地址是用的是iframe,这种没有技术含量的方法让人很不爽。于是用这个域名重新申请了一个空间,然后把域名的dns设置为免费空间的dns,想把域名直接指向我的blog。但是dns改了几次,老是出问题。每改一次都要等很久才能看到结果,真把我等郁闷了。最后发现ms是子域名的A记录设置有问题,不过问题还没确认,目前还在等待中-_-!

posted @ 7:31 | Feedback (0)

2007年4月29日

昨天晚上找了一个漂亮的wordpress模板,然后以海贼王为主题修改了一下(图片好难搞,改的好辛苦>_<)。

改css时候还遇到一个问题:动态宽度的块级元素的居中。居中一个块级元素常用的办法是设置待居中元素的宽度,然后将水平方向的空白边设为auto,例如:"width:100px;margin:0 auto;"。但是当这个块级元素的宽度不确定的时候就不好办了。在ie中,可以将text-align属性设为center来居中块级元素(text-align本来只对文本起作用的,算是ie的一个bug吧);在非ie浏览器中,我还没找到很好的解决方法,这里顺便请教一下。

最后推荐一下firefox的一个插件:firebug。异常强大实用的东东,无论是排版页面,调试脚本,测试连接速度等等都很好用,功能很全面,改blog全靠它了。

posted @ 21:19 | Feedback (0)

blog已经转移至www.myjojo.com.cn :)

posted @ 20:11 | Feedback (0)

2006年11月20日

0.1beta:鼠标移到提示框上提示框不消失
0.2beta:优化了类,分离了一些控制样式的代码
0.3beta:支持控制提示框的显示位置
0.4beta:增加了提示框消失延迟,可设置延迟的长短
0.41beta:支持firefox
ps:0.5 预告——增加淡入淡出效果


<html>
<head runat="server">
    <title>无标题页</title>

    <style>
    #testarea
 {
  width:100px;
  height:100px;
  background-color: Silver;
  margin-top:50px;
 }
 .board
 {
  background-color: Red;
 }
    </style>

    <script type="text/javascript">
    //显示提示框的类
    var detail={
     "db":document.createElement("div"),  //新建div作为提示框
     "d":null,        //被提示的DIV
     "verD":20,    //提示框在被提示DIV内的边与被提示DIV水平边的垂直距离
     "horD":20,   //提示框在被提示DIV内的边与被提示DIV水平边的水平距离
     "timer":null,
     "duration":500,                        //提示框消失的延迟,单位毫秒
     "create":function(){
         detail.db.className="board";         /提示框的类名(用于通过CSS控制样式)
         detail.db.style.width="200px";           //提示框的宽
         detail.db.style.height="200px";          //提示框的高
         detail.db.style.position="absolute";
         detail.db.onmouseout=function(){
             detail.timer=setTimeout("detail.d.offsetParent.removeChild(detail.db)",
                    detail.duration );
         };
         detail.db.onmouseover=function(){
             clearTimeout(detail.timer);
         };
     },
     "show":function(d,horMode,verMode){  //horMode:0向右显示提示;1向左显示提示。
                                                                          //verMode:0向上显示提示;1向下显示提示。
         clearTimeout(detail.timer);
         detail.d=d;
         detail.d.onmouseout=function(e){
             var toElement=e?e.relatedTarget:window.event.toElement;
             if(toElement.className!="board")
                 detail.timer=setTimeout("detail.d.offsetParent.removeChild(detail.db)",
                    detail.duration );
         };
         detail.create();
         var dbHeight=parseInt(detail.db.style.height);
         var dbWidth=parseInt(detail.db.style.width);
         var offY=0;
         var offX=0;
         if(horMode) offY=dbHeight+d.offsetHeight-2*detail.verD;
         if(verMode) offX=dbWidth+d.offsetWidth-2*detail.horD;
         detail.db.style.top=d.offsetTop-dbHeight+detail.verD+offY+"px";
         detail.db.style.left=d.offsetLeft+d.offsetWidth-detail.horD-offX+"px";
         d.offsetParent.appendChild(detail.db);
         return detail.db;
     }
 }

function showDetail(d,horMode,verMode)
{
   var board=detail.show(d,horMode,verMode);
   if(board.childNodes.length>0)
   board.removeChild(board.firstChild);
   board.appendChild(document.createTextNode("提示信息"));
}

</script>

</head>

<body>
    <form id="form1" runat="server">
        <div>
            <div id="testarea" onmouseover="showDetail(this,1,0)">
            test area
            </div>
        </div>
    </form>
</body>

</html>

posted @ 19:57 | Feedback (3)

2006年11月15日

比如可以在textarea中显示一个表格:

<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>test</title>
</head>

<body>
<table border="1" width="100%" id="tab">
 <tr>
  <td width="50%"> </td>
  <td width="50%"> </td>
 </tr>
 <tr>
  <td> </td>
  <td> </td>
 </tr>
</table>
<textarea rows="30" cols="100" id="txt">
</textarea>
<script>

//关键!
document.getElementById("txt").appendChild(document.getElementById("tab"))
</script>
</body>

</html>

有意思的是在textarea中的表格可以通过拖动改变大小,不知道为什么。请教高手……

posted @ 18:19 | Feedback (1)

2006年11月8日

     SDK 就是 Software Development Kit 的缩写,就是“软件开发工具包”。
这是一个覆盖面相当广泛的名词,可以这么说:辅助开发某一类软件的相关文档、
范例和工具的集合都可以叫做“SDK”。具体到我们这个系列教程,我们后面只讨
论广义 SDK 的一个子集——即开发 Windows 平台下的应用程序所使用的 SDK。
    呵呵,其实上面只是说了一个 SDK 大概的概念而已,理解什么是 SDK
真有这么容易吗?恐怕没这么简单!为了解释什么是 SDK 我们不得不引入
API、动态链接库、导入库等等概念。^_^,不要怕,也就是几个新的名词而已,
我也是到了大学快结束的时候才体会到其实学习新知识就是在学习新名词、
新概念和新术语。
    首先要接触的是“API”,也就是 Application Programming Interface,
其实就是操作系统留给应用程序的一个调用接口,应用程序通过调用操作系统的
API 而使操作系统去执行应用程序的命令(动作)。其实早在 DOS 时代就有
API 的概念,只不过那个时候的 API 是以中断调用的形式(INT 21h)提供的,
在 DOS 下跑的应用程序都直接或间接的通过中断调用来使用操作系统功能,
比如将 AH 置为 30h 后调用 INT 21h 就可以得到 DOS 操作系统的版本号。
而在 Windows 中,系统 API 是以函数调用的方式提供的。同样是取得操作
系统的版本号,在 Windows 中你所要做的就是调用 GetVersionEx() 函数。
可以这么说,DOS API 是“Thinking in 汇编语言”的,而 Windows API
则是“Thinking in 高级语言”的。DOS API 是系统程序的一部分,他们
与系统一同被载入内存并且可以通过中断矢量表找到他们的入口,那么
Windows API 呢?要说明白这个问题就不得不引入我们下面要介绍得这
个概念——DLL。
    DLL(又是一个缩写,感觉 IT 这个行业里三字头缩写特别多),即
Dynamic Link Library(动态链接库)。我们经常会看到一些 .dll
格式的文件,这些文件就是动态链接库文件,其实也是一种可执行文件格式。
跟 .exe 文件不同的是,.dll 文件不能直接执行,他们通常由 .exe 在执行
时装入,内含有一些资源以及可执行代码等。其实 Windows 的三大模块就是
以 DLL 的形式提供的(Kernel32.dll,User32.dll,GDI32.dll),里面就
含有了 API 函数的执行代码。为了使用 DLL 中的 API 函数,我们必须要有
API 函数的声明(.H)和其导入库(.LIB),函数的原型声明不难理解,
那么导入库又是做什么用的呢?我们暂时先这样理解:导入库是为了在 DLL
中找到 API 的入口点而使用的。
    所以,为了使用 API 函数,我们就要有跟 API 所对应的 .H 和 .LIB
文件,而 SDK 正是提供了一整套开发 Windows 应用程序所需的相关文件、
范例和工具的“工具包”。到此为止,我们才真正的解释清楚了 SDK 的含义。
    由于 SDK 包含了使用 API 的必需资料,所以人们也常把仅使用 API
来编写 Windows 应用程序的开发方式叫做“SDK 编程”。而 API 和 SDK
是开发 Windows 应用程序所必需的东西,所以其它编程框架和类库都是
建立在它们之上的,比如 VCL 和 MFC,虽然他们比起“SDK 编程”来有着
更高的抽象度,但这丝毫不妨碍它们在需要的时候随时直接调用 API 函数。

posted @ 18:30 | Feedback (1)

2006年11月1日

  • 资料1:

数据处理方式:
  当浏览器通过各种请求方法,试图从服务器获得数据的时候,服务器就必须将正确的数据返回给浏览器。浏览器并不关心服务器是如何进行处理的,服务器可以返回一个预先编辑好的HTML文档,也能根据请求动态生成返回的数据。而WWW的一大特点就是能用来传送多媒体数据,并且这些数据的传送是完全透明的,通过同样的HTTP连接,可以传送不同格式的声音、图象等数据。当服务器仅仅用于返回静态的HTML文档的时候,浏览器能够很容易的识别其数据类型,但当服务器不但用于返回静态的HTML文档,还可以动态返回各种类型的多媒体信息时,浏览器就不能仅仅从URL请求本身上判断服务器将会返回何种数据了。
  服务器和浏览器之间是采用了另外的方式来标识数据的类型,这种方式下通过在传输真正的数据之前,预先传输一个数据的MIME类型的方法,来标识数据类型。
多媒体文件格式MIME:
  最早的HTTP协议中,并没有附加的数据类型信息,所有传送的数据都被客户程序解释为超文本标记语言HTML 文档,而为了支持多媒体数据类型,HTTP协议中就使用了附加在文档之前的MIME数据类型信息来标识数据类型。
  MIME意为多目的Internet邮件扩展,它设计的最初目的是为了在发送电子邮件时附加多媒体数据,让邮件客户程序能根据其类型进行处理。然而当它被HTTP协议支持之后,它的意义就更为显著了。它使得HTTP传输的不仅是普通的文本,而变得丰富多彩。
  每个MIME类型由两部分组成,前面是数据的大类别,例如声音audio、图象image等,后面定义具体的种类。
常见的MIME类型:
超文本标记语言文本 .html,.html text/html
普通文本 .txt text/plain
RTF文本 .rtf application/rtf
GIF图形 .gif image/gif
JPEG图形 .ipeg,.jpg image/jpeg
au声音文件 .au audio/basic
MIDI音乐文件 mid,.midi audio/midi,audio/x-midi
RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio
MPEG文件 .mpg,.mpeg video/mpeg
AVI文件 .avi video/x-msvideo
GZIP文件 .gz application/x-gzip
TAR文件 .tar application/x-tar
  Internet中有一个专门组织IANA(Internet Assigned Numbers Athority)来确认标准的MIME类型,但Internet发展的太快,很多应用程序等不及IANA来确认他们使用的MIME类型为标准类型。因此他们使用在类别中以x-开头的方法标识这个类别还没有成为标准,例如:x-gzip,x-tar等。事实上这些类型运用的很广泛,已经成为了事实标准。只要客户机和服务器共同承认这个MIME类型,即使它是不标准的类型也没有关系,客户程序就能根据MIME类型,采用具体的处理手段来处理数据。而Web服务器和浏览器(包括操作系统)中,缺省都设置了标准的和常见的MIME类型,只有对于不常见的 MIME类型,才需要同时设置服务器和客户浏览器,以进行识别。
  由于MIME类型与文档的后缀相关,因此服务器使用文档的后缀来区分不同文件的MIME类型,服务器中必须定义文档后缀和MIME类型之间的对应关系。而客户程序从服务器上接收数据的时候,它只是从服务器接受数据流,并不了解文档的名字,因此服务器必须使用附加信息来告诉客户程序数据的MIME类型。服务器在发送真正的数据之前,就要先发送标志数据的MIME类型的信息,这个信息使用Content-type关键字进行定义,例如对于HTML文档,服务器将首先发送以下两行MIME标识信息,这个标识并不是真正的数据文件的一部分。
  Content-type: text/html
  注意,第二行为一个空行,这是必须的,使用这个空行的目的是将MIME信息与真正的数据内容分隔开。
PS:IANA确认的标准的MIME类型见
http://www.iana.org/assignments/media-types/

  • 资料2:

正确设置服务器端MIME的类型对于顺利播放Flash电影非常重要,因为你需要通过服务器告诉浏览器发送的是何种类型文件,从而使浏览器在接收网上文件时知道进行何种操作。在播放Flash电影时,服务器会通知浏览器应使用其内置插件来播放接收到的信息。
如果MIME类型设置错误,则有可能会出现以下几种情况:
*出现错误提示图标
*浏览器崩溃出错
*显示空白图片
*仅显示一个Flash图标
*弹出错误信息对话框
*弹出对话框要求用户保存该文件
*弹出对话框要求用户选择相应程序来运行接收到的文件

posted @ 22:12 | Feedback (0)

我们在网页上嵌入多媒体的时候,常常使用<object>(FF不支持)或<embed>标记。但embed 标签从来都不是 HTML 标准中的标签,因此 XHTML 中也没有它。所以如果使用embed标记的话是无法通过XHTML验证的。

我们知道 W3C 推荐使用的是 object 标签,但用法却不是 Internet Explorer 那种用 classid 来区分控件类型,而是采用 type 来指定 MIME 类型。现在的 Mozilla、Firefox 和 Opera 都支持这种用法,虽然 IE 目前的版本也支持这种用法,不过很可惜的是,IE 还是有 bug,那就是只有全部下载完毕才能播放。而且还不是所有的情况下都能用。在某些 IE 浏览器上还显示空白。所以单纯用 W3C 推荐的 object 标签用法还是不够的。但是我们可以作一下变通,如果是用户浏览器是 IE 的话,我们就用 IE 的 object 的用法,如果是其他浏览器,我们就采用 W3C 的用法。这样就可以两全其美了。也许此刻,你觉得我们该用到脚本了。不,我们不需要脚本。我们只需要用 IE 所特有的条件注释和 CSS 就可以做到了。例子如下:
<style type="text/css">
.mozilla {
  display:block;
}
</style>
<!--[if IE]>
<style type="text/css">
.mozilla {
  display:none;
}
</style>
<![endif]-->
 
<object
  data="flashdatei.swf"
  type="application/x-shockwave-flash"
  height="275"
  width="256"
  class="mozilla">
  <param name="autoplay" value="true">
</object>
<!--[if IE]>
<object
  classid="cclsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  width="256"
  height="275">
  <param name="src" value=""flashdatei.swf">
</object>
<![endif]-->
你会发现其实就是把 embed 替换成了 object,而且位置也从 IE 的 object 中移出来了。embed 标签里的 src 属性在 object 中变成了 data 属性。而 firefox 等非 IE 浏览器因为不认识 <!–[if IE]> 标签,所以其中的部分都当作注释忽略了。而 IE 因为执行了 <!–[if IE]> 中的内容,所以 firefox 中可以识别的那个 object 因为 css 被重新定义而被隐藏了。

以上为转贴!

这段文字中提到MIME 类型,开始看的时候不知道是什么东西,于是Google了一下,发现里面还有不少文章。我把收集到的一些MIME类型的资料放在下一篇随笔中。

posted @ 21:55 | Feedback (0)

2006年10月30日

在XMLHttpRequest出现之前,经常使用这种方法来实现不用刷新整个页面,下面是一个简单的例子:

RemoteScriptingTest.htm:

<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset="iso-8859-1" />
  <title>RemoteScriptingTest</title>
  <script type="text/javascript">
   function getMsg(message)
   {
    var s=document.getElementById("show");
    s.innerText=message;
   }
  </script>
 </head>
 <body>
  <iframe name="ifr" src="blank.htm" style="width:0px;height:0px;border:0px;"></iframe>
  <a href="server.htm" target="ifr">call the server</a>
  <div id="show">test message</div>
 </body>
</html>

server.htm:

<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset="iso-8859-1" />
  <title>server</title>
  <script type="text/javascript">
   window.parent.getMsg("this is the message from the server..."); 
  </script>
 </head>
 <body>
 </body>
</html>

这个例子实际上只刷新了IFRAME里面的页面,通过这种方法可以实现MS无刷新的情况下与服务器通信。其实这个和AJAX的原理也有点类似...

posted @ 22:48 | Feedback (0)

通常文本框输入的时候会提示以前输入的内容,用aotocomplete可以控制是否提示:
 
<input name="ok" type="text" autocomplete="off">

posted @ 13:51 | Feedback (1)

2006年10月26日

  • 怎样在Window.Open打开的新窗口里获取父窗口里的对象:

opener property:Sets or retrieves a reference to the window that created the current window.

eg.   window.opener.document.getElementByID(...)

  • 在iframe里获取父窗口里的对象:

parent.ducument...

  • 加载图片时显示“图片加载中……”:为IMG设置ONLOAD事件

eg:  <div id="pic">图片加载中……</div><img src="http://bbs.51js.com/images/default/newtopic.gif" style="display:none;"

onload="this.style.display='inline';document.getElementById('pic').style.display='none';">

  • 指定时间后自动后退(代码转自51js):

<p>对不起,你发布信息的时间隔太短,请过两分钟再试</p>
<p>页面将于 <span id="txt">5</span> 秒钟后自动返回..
<script>
function a() {
alert(document.getElementById("txt").firstChild.data);
  if((--document.getElementById("txt").firstChild.data)==0)
    window.history.back();
  else
    setTimeout("a()",1000);
}
setTimeout("a()",1000);
</script>

  • alert()会让页面失去焦点,会自动触发onmouseout事件。
  • 文本框的两个有用的事件:

onfocus="function()" :进入编辑状态时触发;onblur="function()" :结束编辑状态时触发。

  • script标签的defer属性:script标签加上defer属性后,标签里的脚本会在页面加载完成之后才执行。

posted @ 23:11 | Feedback (0)

2006年10月25日

刚刚学到的,嘿嘿……

<style type="text/css">
 <!--
 tr {background-color:expression((this.sectionRowIndex%2==0)?"red":"blue")}
 -->
 </style>
 </HEAD>
 <table>
 <tr><td>第1行</td><td>第1行</td></tr>
 <tr><td>第2行</td><td>第2行</td></tr>
 <tr><td>第3行</td><td>第3行</td></tr>
 <tr><td>第4行</td><td>第4行</td></tr>
 <tr><td>第5行</td><td>第5行</td></tr>
 </table>

expression(JS表达式):得到JS表达式的值;上面的代码是控制表格的交替颜色。

posted @ 22:25 | Feedback (4)

 刚看了一篇文章:“画中画”效果---谈Iframe标记的使用 (http://bbs.51js.com/viewthread.php?tid=12349)。由此想到我们电影站没有用好iframe,本来像侧边导航条和banner之类的,页面与页面之间没什么变化,不用刷新,用iframe的话能很大程度上提高浏览体验。以后改版的时候一定注意。

posted @ 22:12 | Feedback (0)

2006年10月10日

ASP.NET提供三种主要形式的缓存:页面级输出缓存、用户控件级输出缓存(或称为片段缓存)和缓存API。输出缓存和片段缓存的优点是非常易于实现,在大多数情况下,使用这两种缓存就足够了。而缓存API则提供了额外的灵活性(实际上是相当大的灵活性),可用于在应用程序的每一层利用缓存。本文全面介绍了这三种缓存技术在系统各层中的应用。

  在ASP.NET提供的许多特性中,缓存支持无疑是我最欣赏的特性,我这样说当然是有充分理由的。相比ASP.NET的所有其他特性,缓存对应用程序的性能具有最大的潜在影响,利用缓存和其他机制,ASP.NET开发人员可以接受使用开销很大的控件(例如,DataGrid)构建站点时的额外开销,而不必担心性能会受到太大的影响。为了在应用程序中最大程度地利用缓存,您应该考虑在所有程序级别上都实现缓存的方法。

  Steve的缓存提示

  尽早缓存;经常缓存

  您应该在应用程序的每一层都实现缓存。向数据层、业务逻辑层、UI或输出层添加缓存支持。内存现在非常便宜-因此,通过以智能的方式在整个应用程序中实现缓存,可以获得很大的性能提高。

  缓存可以防止许多过失

  缓存是一种无需大量时间和分析就可以获得“足够良好的”性能的方法。这里再次强调,内存现在非常便宜,因此,如果您能通过将输出缓存30秒,而不是花上一整天甚至一周的时间尝试优化代码或数据库就可以获得所需的性能,您肯定会选择缓存解决方案(假设可以接受30秒的旧数据)。缓存正是那些利用20%付出获得80%回报的特性之一,因此,要提高性能,应该首先想到缓存。不过,如果设计很糟糕,最终却有可能带来不良的后果,因此,您当然也应该尽量正确地设计应用程序。但如果您只是需要立即获得足够高的性能,缓存就是您的最佳选择,您可以在以后有时间的时候再重新设计应用程序。

  页面级输出缓存

  作为最简单的缓存形式,输出缓存只是在内存中保留为响应请求而发送的HTML的副本。其后再有请求时将提供缓存的输出,直到缓存到期,这样,性能有可能得到很大的提高(取决于需要多少开销来创建原始页面输出-发送缓存的输出总是很快,并且比较稳定)。

  实现

  要实现页面输出缓存,只要将一条OutputCache指令添加到页面即可。

<%@ OutputCache Duration="60" VaryByParam="*" %>

  如同其他页面指令一样,该指令应该出现在ASPX页面的顶部,即在任何输出之前。它支持五个属性(或参数),其中两个是必需的。

  Duration 必需属性。页面应该被缓存的时间,以秒为单位。必须是正整数。

  Location 指定应该对输出进行缓存的位置。如果要指定该参数,则必须是下列选项之一:Any、Client、Downstream、None、Server或ServerAndClient。

  VaryByParam 必需属性。Request中变量的名称,这些变量名应该产生单独的缓存条目。“none”表示没有变动。“*”可用于为每个不同的变量数组创建新的缓存条目。变量之间用“;”进行分隔。

  VaryByHeader 基于指定的标头中的变动改变缓存条目。

  VaryByCustom 允许在global.asax中指定自定义变动(例如,“Browser”)。

  利用必需的Duration和VaryByParam选项的组合可以处理大多数情况。例如,如果您的产品目录允许用户基于categoryID和页变量查看目录页,您可以用参数值为“categoryID;page”的VaryByParam将产品目录缓存一段时间(如果产品不是随时都在改变,一小时还是可以接受的,因此,持续时间是3600秒)。这将为每个种类的每个目录页创建单独的缓存条目。每个条目从其第一个请求算起将维持一个小时。
VaryByHeader和VaryByCustom主要用于根据访问页面的客户端对页面的外观或内容进行自定义。同一个URL可能需要同时为浏览器和移动电话客户端呈现输出,因此,需要针对不同的客户端缓存不同的内容版本。或者,页面有可能已经针对IE进行了优化,针对Netscape或Opera则应取消这种优化功能。后一个例子非常普遍,我们将提供一个说明如何实现此目标的示例:

  示例:VaryByCustom用于支持浏览器自定义

  为了使每个浏览器都具有单独的缓存条目,VaryByCustom的值可以设置为“browser”。此功能已经内置在缓存模块中,并且将针对每个浏览器名称和主要版本插入单独的页面缓存版本。

<%@ OutputCache Duration="60" VaryByParam="None" VaryByCustom="browser"%>

  片段缓存,用户控件输出缓存

  缓存整个页面通常并不可行,因为页面的某些部分是针对用户定制的。不过,页面的其他部分是整个应用程序共有的。这些部分最适合使用片段缓存和用户控件进行缓存。此外,菜单和其他布局元素,尤其是那些从数据源动态生成的元素,也可以用这种方法进行缓存。

  如果需要,可以按以下条件选择需要缓存的控件

  (1)某控件的属性已改变

  (2)由页面级输出缓存所支持的任何一种页面或控件状态改变

  一旦对某些控件进行了缓存,使用它们的几百个页面就可以共享这些控件,而不再需要为每个页面保留单独的控件缓存版本。

  实现

  片段缓存使用的语法与页面级输出缓存一样,但其应用于用户控件(.ascx文件)而不是Web窗体(.aspx文件)。除了Location属性,对于OutputCache在Web窗体上支持的所有属性,用户控件也同样支持。用户控件还支持名为VaryByControl的OutputCache属性,该属性将根据用户控件(通常是页面上的控件,例如,DropDownList)的成员的值改变该控件的缓存。如果指定了VaryByControl,可以省略VaryByParam。最后,在默认情况下,对每个页面上的每个用户控件都单独进行缓存。不过,如果一个用户控件不随应用程序中的页面改变,并且在所有页面都使用相同的名称,则可以设置参数Shared的值为“true”,该参数将使用户控件的缓存版本供引用该控件的所有页面使用。

  示例

<%@ OutputCache Duration="60" VaryByParam="*" %>

  该示例将缓存用户控件60秒,并且将针对查询字符串的每个变动、针对此控件所在的每个页面创建单独的缓存条目。

<%@ OutputCache Duration="60" VaryByParam="none"
VaryByControl="CategoryDropDownList" %>

  该示例将缓存用户控件60秒,并且将针对CategoryDrop

  DownList控件的每个不同的值、针对此控件所在的每个页面创建单独的缓存条目。

<%@ OutputCache Duration="60" VaryByParam="none" VaryByCustom="browser"
Shared="true" %>

  最后,该示例将缓存用户控件60秒,并且将针对每个浏览器名称和主要版本创建一个缓存条目。然后,每个浏览器的缓存条目将由引用此用户控件的所有页面共享(只要所有页面都用相同的ID引用该控件即可)。

  缓存API,使用Cache对象

  页面级和用户控件级输出缓存的确是一种可以迅速而简便地提高站点性能的方法,但是在ASP.NET中,缓存的真正灵活性和强大功能是通过Cache对象提供的。使用Cache对象,您可以存储任何可序列化的数据对象,基于一个或多个依赖项的组合来控制缓存条目到期的方式。这些依赖项可以包括自从某对象被缓存后经过的时间、自从某对象上次被访问后经过的时间、对文件或文件夹的更改以及对其他缓存对象的更改,在略作处理后还可以包括对数据库中特定表的更改。

  在Cache中存储数据

  在Cache中存储数据的最简单的方法就是使用一个键为其赋值,就像HashTable或Dictionary对象一样:

Cache["key"] = "value";

  这种做法将在缓存中存储项,同时不带任何依赖项,因此它不会到期,除非缓存引擎为了给其他缓存数据提供空间而将其删除。要包括特定的缓存依赖项,可使用Add()或Insert()方法。其中每个方法都有几个重载。Add()和Insert()之间的唯一区别是,Add()返回对已缓存对象的引用,而Insert()没有返回值(在C#中为空,在VB中为Sub)。

  示例

Cache.Insert("key", myXMLFileData, new
System.Web.Caching.CacheDependency(Server.MapPath("users.xml")));

  该示例可将文件中的xml数据插入缓存,无需在以后请求时从文件读取。CacheDependency的作用是确保缓存在文件更改后立即到期,以便可以从文件中提取最新数据,重新进行缓存。如果缓存的数据来自若干个文件,还可以指定一个文件名的数组。

Cache.Insert("dependentkey", myDependentData, new
System.Web.Caching.CacheDependency(new string[] {}, new string[]
{"key"}));

  该示例可插入键值为“key”的第二个数据块(取决于是否存在第一个数据块)。如果缓存中不存在名为“key”的键,或者如果与该键相关联的对象已到期或被更新,则“dependentkey”的缓存条目将到期。

Cache.Insert("key", myTimeSensitiveData, null,
DateTime.Now.AddMinutes(1), TimeSpan.Zero);

  绝对到期:此示例将对受时间影响的数据缓存一分钟,一分钟过后,缓存将到期。注意,绝对到期和滚动到期(见下文)不能一起使用。

Cache.Insert("key", myFrequentlyAccessedData, null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
TimeSpan.FromMinutes(1));

  动态滚动到期:此示例将缓存一些频繁使用的数据。数据将在缓存中一直保留下去,除非数据未被引用的时间达到了一分钟。注意,动态滚动到期和绝对到期不能一起使用。

  更多选项

  除了上面提到的依赖项,我们还可以指定项的优先级(依次为low、high、NotRemovable,它们是在System.Web.Caching.CacheItemPriority枚举中定义的)以及当缓存中的对象到期时调用的CacheItemRemovedCallback函数。大多数时候,默认的优先级已经足够了-缓存引擎可以正常完成任务并处理缓存的内存管理。CacheItemRemovedCallback选项考虑到一些很有趣的可能性,但实际上它很少使用。不过,为了说明该方法,我将提供它的一个使用示例:

  CacheItemRemovedCallback示例

System.Web.Caching.CacheItemRemovedCallback callback = new System.Web.Caching.CacheItemRemovedCallback (OnRemove);
Cache.Insert("key",myFile,null,
 System.Web.Caching.Cache.NoAbsoluteExpiration,
 TimeSpan.Zero,
 System.Web.Caching.CacheItemPriority.Default, callback);
. . .
public static void OnRemove(string key, object cacheItem,
 System.Web.Caching.CacheItemRemovedReason reason)
{
 AppendLog("The cached value with key '" + key +
"' was removed from the cache. Reason: " +
 reason.ToString());
}

  该示例将使用AppendLog()方法中定义的任何逻辑来记录缓存中的数据到期的原因。通过在从缓存中删除项时记录这些项并记录删除的原因,您可以确定是否在有效地使用缓存或者您是否可能需要增加服务器上的内存。注意,callback是一个静态(在VB中为Shared)方法,建议使用该方法的原因是,如果不使用它,保存回调函数的类的实例将保留在内存中,以支持回调(对static/Shared方法则没有必要)。

  该特性有一个潜在的用处-在后台刷新缓存的数据,这样用户永远都不必等待数据被填充,但数据始终保持相对较新的状态。但实际上,此特性并不适用于当前版本的缓存API,因为在从缓存中删除缓存的项之前,不触发或不完成回调。因此,用户将频繁地发出尝试访问缓存值的请求,然后发现缓存值为空,不得不等待缓存值的重新填充。我希望在未来的ASP.NET版本中看到一个附加的回调,可以称为CachedItemExpiredBut

  NotRemovedCallback,如果定义了该回调,则必须在删除缓存项之前完成执行。

  缓存数据引用模式

  每当我们尝试访问缓存中的数据时,都应该考虑到一种情况,那就是数据可能已经不在缓存中了。因此,下面的模式应该普遍适用于您对缓存的数据的访问。在这种情况下,我们假定已缓存的数据是一个数据表。

public DataTable GetCustomers(bool BypassCache)
{
 string cacheKey = "CustomersDataTable";
 object cacheItem = Cache[cacheKey] as DataTable;
 if((BypassCache) (cacheItem == null))
 {
  cacheItem = GetCustomersFromDataSource();
  Cache.Insert(cacheKey, cacheItem, null,
  DateTime.Now.AddSeconds(GetCacheSecondsFromConfig(cacheKey), TimeSpan.Zero);
 }
 return (DataTable)cacheItem;
}

  关于此模式,有以下几点需要注意:

  1) 某些值(例如,cacheKey、cacheItem和缓存持续时间)是一次定义的,并且只定义一次。

  2) 可以根据需要跳过缓存-例如,当注册一个新客户并重定向到客户列表后,最好的做法可能就是跳过缓存,用最新数据重新填充缓存,该数据包括新插入的客户。

  3) 缓存只能访问一次。这种做法可以提高性能,并确保不会发生NullReferenceExceptions,因为该项在第一次被检查时是存在的,但第二次检查之前就已经到期了。

  4) 该模式使用强类型检查。C#中的“as”运算符尝试将对象转换为类型,如果失败或该对象为空,则只返回null(空)。

  5) 持续时间存储在配置文件中。在理想的情况下,所有的缓存依赖项(无论是基于文件的,或是基于时间的,还是其他类型的依赖项)都应该存储在配置文件中,这样就可以进行更改并轻松地测量性能。我还建议您指定默认缓存持续时间,而且,如果没有为所使用的cacheKey指定持续时间,就让GetCacheSecondsFromConfig()方法使用该默认持续时间。

  与本文相关的代码示例(CachedDemo.msi,参见本书示例光盘)是一个helper类,它将处理上述所有情况,可以只书写一行或两行代码访问缓存的数据。

  小结

  缓存可以使应用程序的性能得到很大的提高,因此在设计应用程序以及对应用程序进行性能测试时应该予以考虑。应用程序总会或多或少地受益于缓存,当然有些应用程序比其他应用程序更适合使用缓存。对ASP.NET提供的缓存选项的深刻理解是任何ASP.NET开发人员应该掌握的重要技巧。

posted @ 12:27 | Feedback (1)