An error happend in setEntries() of RSSGenerator.java


2006-12-11 08:12:11,875 - get feed of latestAdvicesOfGoal:feedType=rss_2.0 entriesNum=10 channelID=2747, channelName is:注册用户公告信息发布区; User: unknown IP: 65.55.212.140 USER-AGENT: msnbot-media/1.0 (+http://search.msn.com/msnbot.htm) REFERER: null

2006-12-11 08:12:12,953 - User: userID:-1,userName:guest; IP: 65.55.212.140 USER-AGENT: msnbot-media/1.0 (+http://search.msn.com/msnbot.htm) REFERER: null

2006-12-11 08:12:15,593 - An error happend in setEntries() of RSSGenerator.javaYou have an error in your SQL syntax.  Check the manual that corresponds to your MySQL server version for the right syntax to use near ') ORDER BY writeDate DESC' at line 1

2006-12-11 08:12:15,609 - get feed of latestAdvicesOfMyDiaries:feedType=rss_2.0 entriesNum=10 userName=guest; User: unknown IP: 65.55.212.140 USER-AGENT: msnbot-media/1.0 (+http://search.msn.com/msnbot.htm) REFERER: null

RSS订阅在thunderbird中有时会出现丢失条目的情况,但是在新浪点点通和其它RSS阅读器中又没有发现问题。

而且,我时不时在网站日志中发现上面的错误信息“An error happend in setEntries() of RSSGenerator.java”。

现在把它记在这里,好好查一查,说不定能找出在thunderbird中RSS订阅有问题的情况。

怎样检测网址返回的头部信息状态码(比如是否301重定向)

我还没有发现哪个中文网站提供这个功能。

用 url header checker这三个单词作为关键字在google中我找到两个我主要使用的网址返回的头部信息状态码检测的网站。

http://web-sniffer.net/

http://www.webconfs.com/http-header-check.php

您把要检测的网址输入对话框中,提交后,这些网站就会告诉您这个网址返回的头部信息状态码

如果您的网址返回200 OK表示您的这个网址是正常的,要在网上推广的网址。如果一个相同的页面有两个或两个以上的网址都返回200 OK,那么其中多出来的网址会被搜索引擎看成复制内容的网页,要受负面影响甚至惩罚直至删除网站索引。

在上面的有多个200 OK码的情况下,您应该把多余的网址用301永久重定向到你要推广的网址(也就是在上面检测中返回状态码200 OK的网址),在上面的检测中,作了301重定向的网址应该返回301状态码;

还有一个重定向是302,它指的是临时的转向。具体您可以搜索一下相关内容。

在使用上面检测网站一个非常重要的地方就是:



且记:当您改变了网页的重定向,重新检测重定向效果时,一定要刷新一下检测页面。不然,显出的结果有可能是上次检测结果缓存在本地计算机的旧页面!!!

另外,关于301重定向,本站有下列几篇日记可供参考:

301重定向技术汇总(转)

JSP/servlet中<JSP:FORWORD>和response.sendRedirect ...

昨天去掉了网站的动态导航参数并做301定向

百度和google对本站301重定向的反应

混乱的日子

这几天的思维和行动都有些混乱了。

1、网页静态化整体方案;

2、JAVA学习日记到底使用http://www.learndiary.com/java/(主站二级目录)还是http://java.learndiary.com/(二级独立域名)?有点后悔见到zac的时间迟了那么一点点。否则,JAVA学习日记有可能采用二级目录;

3、防垃圾留言;

4、学习设计模式;

5、单位职称计算机考试又马上又来了,虽然我一天都摸计算机,可是都是用的linux,考试用的是windows系统,好多东西没摸,怕是忘了不少,到时考不过才丢人;

6、单位改革;

事情真多呀,虽然好多是自找的麻烦。

考虑的结果,因为未知和变数太多,所以:

1、仅首页静态化,做全站的jsp文件的网站地图,用jsp做也是为了以后的适应变动要灵活点,可以用程序的方式处理比如转向,过滤什么的;

2、保持二级独立域名不变,不然这个网站和我这个人都太善变了,而且这样问题也不是很大,变动是绝对的,静止是相对的。要变,以后有必要的时候再说。要不然,一直保持这个以JAVA学习为主的站也可以。以后假设开拓其它的领域就在www.learndiary.com做二级目录吧。JAVA是我的初恋情人,不妨给她点特殊地位;)

3、现在没必要写防垃圾留言,没人留言,就连垃圾都是渴望的呀:),有垃圾,说明别人看得起你这个站:)

4、5:暂时放慢,学习上以准备计算机考试为主;

6、车到山前必有路,未来是走出来的,不要太压在心上。

java.net.ConnectException: Connection timed out: connect

今天上午10:00开始,空间换IP,中断访问数小时。我在域名控制面板中更改了dns记录,把域名指向新的IP后,大概1个多小时吧,新的域名解析就生效了。原来听说域名解析要6个小时以上才会生效,现在生效时间这么快,是现在的技术更新了,还是只是局部用户访问有效呢(比如外国用户访问时就并没有生效,也就是说全球的IP解析生效不同步)?我就不得而知了。网络方面的知识还是太少了。

空间恢复访问后,基本上是正常。但是我发现本站生成静态文件的部分不能工作了。下面这段代码执行出错:


import java.net.HttpURLConnection;

import java.net.URL;

import java.net.URLConnection;

...

URL url = new URL(str);

URLConnection connection = url.openConnection();

connection.connect();

报错为:


java.net.ConnectException: Connection timed out: connect

后来,连这个状态都达在到了,报错为:


 java.net.UnknownHostException: java.learndiary.com

上网查了资料,感觉下面这个论坛的问题跟我碰到的有点相像:

http://forum.java.sun.com/thread.jspa?threadID=450114&messageID=2043150

其中最后那位朋友的回复启发了我如下:


ckelley114

Posts:1

Registered: 4/5/06

java.net.ConnectException: Connection timed out  

Apr 5, 2006 7:55 AM (reply 3 of 3)

Click to email this message

This is a remote site connection to the internet with a DSL modem and a Cisco pix fire wall. When they get this message they can still use the internet, but can not use the current application. The server is a Windows 2000. To release them they have to cycle the power to the DSL modem and Cisco pix. Can you tell me what is causing this problem?

我连猜带蒙看他的大意是:远程站点通过一个DSL modem和一个Cisco pix防火墙连接到因特网。通过因特网访问能够工作,但是当前的应用访问不能工作,会得到上面的出错信息。是windows2000服务器。解决这个问题必须使访问通过DSL modem和Cisco pix防火墙...

还有另一个地方的答案也与防火墙有关:

转自:(http://www.iexp.com/support/forums/message.cfm?message_ID=260


 

Support Forums

Forums

CFX_RawSocket

java.net.ConnectException: Connection timed out: connect. Java exception occurred in call to method

Subject:  RE: RE: RE: java.net.ConnectException: Connection timed out: connect. Java exception occurred in call to method

Date:  03/18/2004 10:01 AM

Author:  Dominic <oad74@yahoo.com >

  Reply to this message

Just want to appreciate the answer given to this problem. I had the same problem

connectiong to a server behind a firewall and changing

IP address to the machine name works.

bravo!

Dominic

------------

>Hi,

>

>

I guess you might be trying to connect to the

>

server which is behind a firewall. Generally the

>

IP address of the server will be different behind

>

firewall and outside the firewall. So instead of

>

using the IP address if you use the fully qualified

>

host name of the server while connecting, then it

>

will connect without this exception.

>

>

Murali.

>

>

>

------------

>

>------------

>

>

>

>If I implement the tag in Coldfusion and I try to call it it comes back with the error: java.net.ConnectException: Connection timed out: connect. Java exception occurred in call to method. I think this is due to the fact that my server is behind a firewall so uit can't get to the url provided. How can I define a proxy server to connect the URL provided?

的确,通过我的手工输入调用访问上面的代码能够工作。就是空间里的程序本身不能访问。

我试着把域名改为其它的辅助域名(www.learndiary.com或www.123go.org.cn,都是用301重定向到主域名java.learndiary.com的)就一切正常了。

又是一个糊里糊涂的出现问题,糊里糊涂的解决问题的例子。

这叫知其然不知其所以然。没办法,我没有能力去掌握所有的知识和细节。只要解决问题就OK了。

网站地图链接数目和形式及不同静态网页在seo上有无区别

在"搜索引擎优化排名SEO每天一贴"请教了zac关于网站地图链接数目和形式以及静态网页在seo上的效果有无区别。得到解答如下:

摘自:SEO问题解答


  68.  littlebat说:

      2006年12月8日 at 7:16 pm

      zac,您好。

      请问两个问题:

      1、网站地图(即像您网页右下的那个Sitemap)可以放多少链接合适?

      比如,我的站有1000多网页(以后或许更多,比如几十万;)),可不可放在一张网站地图上?

      如果放在一张地图上不好,有两种方式可以放:一是分成几张平行的地图,比如4张,并排放在网页下方;二是在网页下方放一张目录性质的网站地图,然后每个目录又链接到一个下一层次的网站地图;

      2、对于静态网页*.htm,*.html,*.jsp在SEO上哪个要好一点点?我知道您认为:http://www.chinamyhosting.com/seoblog/2006/08/07/seo-questions/

      这样的还要好一点点,不过我问的是上面几种后缀名的比较。

      我问*.jsp的静态网页是因为在*.jsp中可以作一些程序的处理,比如:中文户包含中文的网页提示文字(像按纽文字),非中文用户包含英文的网页提示文字(内容相同)。

  69. Zac说:

      2006年12月9日 at 4:04 am

      littlebat: 最好不要放链接超过100个。你说的第二种处理(分层次)比较好。

      文件后缀名对SEO没有影响。

SCJP认证特惠活动即将停止报名(转帖)

今天早上收到这封邮件,如果有哪位想参加Sun 公司的SCJP技术认证考试的“全国所有大中专院校的全职在读学生”一定要认真看一看。

邮件正文:

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

尊敬的Sun技术社区用户:***

Sun 中国技术社区的注册会员:

我想您之前可能已经通过种种渠道已经得知,在Sun 中国技术社区的大力争取下,全国所有大中专院校的全职在读学生均可在2006年12月31日之前以人民币450 元的学生特惠价格参加Sun 公司的SCJP技术认证考试。在2006年12月31日之后,这个考试将恢复全球统一价格,也就是人民币 1250元。

Sun 公司作为Java语言的发明者,对全球的Java开发人员进行技术水平认证。该认证在国际上获得了IT公司的普遍认可,是目前国际上最热门的IT 认证之一。根据IT认证领域的权威媒体《认证杂志》(Certificate Magazine)的调查结果,在专业背景类似的开发人员当中,拥有 SCJP的开发人员平均起薪要比其他开发人员高21.7% 。诸多国内外IT公司更是在招聘过程中将SCJP认证作为筛选简历的必要手段。

Sun 中国技术社区一直都在努力帮助学习Java的学生获得SCJP技术认证。此次针对大中专学生的SCJP特惠价格,正是在Sun 中国技术社区的大力争取下获得批准。为了帮助同学们顺利通过SCJP考试,我们还组织人力精心编译了一份SCJP复习资料。经过众多稍微具备Java语言基础(在学校上过一个学期的Java课程)的同学实战试用的经验表明,只要根据此复习资料

认真复习两个星期左右,通过SCJP考试的可能性达到90%以上。这份复习资料可以从Sun 中国技术社区的网站免费下载:

http://gceclub.sun.com.cn/SCJP_Guide.pdf

报名参加此次SCJP技术认证考试学生特惠活动,只要如下两个步骤:

(1)至少提前一个星期联系Thomson Prometric全国的考试中心,进行报名。考试中心的联络方式,请通过如下网站查询。由于此次特别优惠活动的截止日期是12月31日,因此您报名的最后期限为12月24日。

http://www.prometric.com.cn/。

(2)持身份证和学生证在约定的考试时间到考试中心进行考试。

如果您对此活动有任何疑问,可以拨打我们的热线电话进行询问,或者发送电子邮件向我们查询。

电话号码:010-62799911,每周一到周六9:00-17:00

电子邮件:chinareg@thomson.com

此外,Sun 中国技术社区于近日向全国大专院校公开招聘20名实习生,负责在校园内宣传和推广Sun 公司的软件技术,包括Java编程语言, NetBeans集成开发环境,以及Solaris 操作系统。我们不要求应聘的学生事先就充分具备这方面的技能,但是希望您能够有较强的学习能力以及与人沟通的能力,能够在短时间内通过培训和自学掌握相应的技术并且能够给身边的同学演示和讲解。因此,我们要求应聘的学生在12月31日之前通过SCJP认证考试,作为学习能力和完成能力的证明。如果您在12月31日之前通过SCJP认证考试并且对我们的实习生职位感兴趣的话,请您将简历发送给 Yang.Wang@Sun.Com。 我们会认真阅读所有的简历,并且通过电话面试决定最终的人选。获得实习生职位的同学,将会被邀请到位于北京的 Sun 工程研究院进行技术培训,并且在Sun 公司资深工程师的指导下在本地开展技术推广工作。在实

习结束之后,Sun 公司会给所有的实习生开具实习工作评估证明,该证明可以作为您寻找下一份工作的推荐信使用。

如果您需要了解Sun 中国技术社区的更多活动,请访问我们的网站:

http://developers.sun.com.cn/。

如果您觉得这封信的内容可能对您的朋友和其他的人有用,请您转发给他们或者是转贴到您经常光顾的网上社区或者论坛。

Sun 中国技术社区

2006年12月09日

Sun技术社区 http://gceclub.sun.com.cn

(退订SUN社区邮件)

********************************************************************************************************

                                                           转帖完毕

不知怎么搞的,系统的邮件发送系统突然失效

今天,我玩意中发现系统的邮件发送系统失效了。也就是说别人订阅了的邮件收不到。

我怀疑是申请的免费的邮箱对这种利用他们的邮箱发邮件有了限制。但是不确定。明天把学习日记自己的邮箱重新启用作邮件发送邮箱试试。

原来,因为学习日记发的邮件常被别的邮件系统当成垃圾邮件(不被其它大的邮件系统信任吧?),所以改用tom.com的邮箱。可是今天不管是tom.com和126.com的邮箱均不能完全的正常工作了。现在想起来,应该用自己的邮箱,就算是被识别为垃圾邮件,也是自己的东西。而且,如果真的有朋友愿意订阅我们的邮件,只要把我们的发送邮箱加入他们邮箱的白名单就行了吧。

*************************************************

补充,这时(距上面的发文半小时后),我才发现可能是tom.com的免费邮箱接收邮件系统出了故障,不能及时收取信件了。因为我把接收学习日记的邮箱改为另一个邮箱后就收到了。而且,我们这个系统的测试帐号的那个邮箱也能收到。明天再看看那些邮件会不会来。

javax.servlet.UnavailableException

今天,我改了几个类文件上传到虚拟空间,应用自动重启不能成功。在log中报告:


2006-12-07 21:25:37,578 - Initializing application data source dataSource

org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (User xyz has already more than 'max_user_connections' active connections)

at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:855)

at org.apache.commons.dbcp.BasicDataSource.setLogWriter(BasicDataSource.java:598)

at org.apache.struts.action.ActionServlet.initModuleDataSources(ActionServlet.java:808)

at org.apache.struts.action.ActionServlet.init(ActionServlet.java:335)

at javax.servlet.GenericServlet.init(GenericServlet.java:82)

at com.caucho.server.http.Application.createServlet(Application.java:3114)

at com.caucho.server.http.Application.loadServlet(Application.java:3065)

at com.caucho.server.http.Application.initServlets(Application.java:1923)

at com.caucho.server.http.Application.init(Application.java:1849)

at com.caucho.server.http.VirtualHost.startApplication(VirtualHost.java:1207)

at com.caucho.server.http.VirtualHost.getInvocation(VirtualHost.java:1007)

at com.caucho.server.http.ServletServer.getInvocation(ServletServer.java:1249)

at com.caucho.server.http.RunnerRequest.handleRequest(RunnerRequest.java:343)

at com.caucho.server.http.RunnerRequest.handleConnection(RunnerRequest.java:274)

at com.caucho.server.TcpConnection.run(TcpConnection.java:139)

at java.lang.Thread.run(Thread.java:595)

Caused by: java.sql.SQLException: User xyz has already more than 'max_user_connections' active connections

at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2928)

at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:771)

at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1229)

at com.mysql.jdbc.Connection.createNewIO(Connection.java:2558)

at com.mysql.jdbc.Connection.<init>(Connection.java:1485)

at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:266)

at org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:37)

at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:290)

at org.apache.commons.dbcp.BasicDataSource.validateConnectionFactory(BasicDataSource.java:877)

at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:851)

... 15 more

2006-12-07 21:25:37,593 - connect fail in CallHtml.callOnePage()!

2006-12-07 21:25:37,593 - excute manager.deleteExpiredRecords() 1 times.

于是,我连接mysql查看当前活动连接数(show porcesslist;)确实达到了空间的最大活动连接数。

然后,只要一进入*.do形式的链接均在页面上报告上面相似的错误。也不知道是我上传的类文件是否触犯了Struts框架哪根神经?

上网用出现错误的关键字查了一下,其中有一篇http://mail-archives.apache.org/mod_mbox/struts-dev/200312.mbox/%3C20031204011632.14053.qmail@nagoya.betaversion.org%3E 上面的话:“Struts missing commons-dbcp and commons-pooling jar files.”启发了我。于是,我把lib中的那个:commons-pool-1.3.jar移走了。然后,我再输入*.do的链接,错误信息变了,为:


2006-12-07 22:11:07,765 - Unable to initialize Struts ActionServlet due to an unexpected exception or error thrown, so marking the servlet as unavailable.  Most likely, this is due to an incorrect or missing library dependency.

java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool

at java.lang.Class.getDeclaredConstructors0(Native Method)

at java.lang.Class.privateGetDeclaredConstructors(Class.java:2328)

at java.lang.Class.getConstructor0(Class.java:2640)

at java.lang.Class.newInstance0(Class.java:321)

at java.lang.Class.newInstance(Class.java:303)

at org.apache.struts.util.RequestUtils.applicationInstance(RequestUtils.java:143)

at org.apache.struts.action.ActionServlet.initModuleDataSources(ActionServlet.java:805)

at org.apache.struts.action.ActionServlet.init(ActionServlet.java:335)

at javax.servlet.GenericServlet.init(GenericServlet.java:82)

at com.caucho.server.http.Application.createServlet(Application.java:3114)

at com.caucho.server.http.Application.loadServlet(Application.java:3065)

at com.caucho.server.http.Application.initServlets(Application.java:1923)

at com.caucho.server.http.Application.init(Application.java:1849)

at com.caucho.server.http.VirtualHost.startApplication(VirtualHost.java:1207)

at com.caucho.server.http.VirtualHost.cron(VirtualHost.java:1359)

at com.caucho.server.http.ServletServer.cron(ServletServer.java:1940)

at com.caucho.server.http.ServletServer.handleCron(ServletServer.java:1774)

at com.caucho.util.Cron$CronThread.evaluateCron(Cron.java:199)

at com.caucho.util.Cron$CronThread.run(Cron.java:163)

2006-12-07 22:11:07,812 - connect fail in CallHtml.callOnePage()!

2006-12-07 22:11:07,812 - excute manager.deleteExpiredRecords() 1 times.

看来,应用已经有反应了(先前是没有任何反应,改变类文件也没反应,log信息一点不变。我又不能手动重启位于虚拟主机上应用,因为他们还暂时不提供这个功能),于是,我再把那个commons-pool-1.3.jar加进去。然后,系统成功自动重启,log信息如下:


2006-12-07 22:12:16,187 - Enter updateCache!

2006-12-07 22:12:21,609 - connect success in CallHtml.callOnePage()!

2006-12-07 22:12:21,609 - excute manager.deleteExpiredRecords() 1 times.

我也不知道是什么原因,就这样糊里糊涂的出问题,又糊里糊涂的解决了问题:)

也许,我中了seo的毒了?

从理论上讲,www.javaeye.com的静态文件列表对搜索引擎来说有内容复制之嫌疑。

如:这篇帖子:confluence不支持群集,是因为hibernate吗?

在静态文件列表中是:http://www.javaeye.com/t/20169.html

而在动态文件列表中是:http://www.javaeye.com/topic/20169

也就是说,相同的内容在他们页面有两个版本,一个动态的,一个静态的。

我不知道这对它们在搜索引擎中的收录有什么影响?

也许,我现在考虑搜索引擎考虑得太多了。

像这两天又想在虚拟主机提供商端实现彻底的301重定向,但是到现在为止也还没有成功。

做网站,或者更坦白的说,学习知识的我不应该在为迁就搜索引擎而折磨自己了。

还有,我发现一个著名的linux个人站linux.vbird.org,他有两个域名:http://linux.vbird.orghttp://www.vbird.org,进入都是同样的返回200 ok状态码;还有他的文章如: DNS 伺服器設定 两个域名都返回的是200码

http://www.vbird.org/linux_server/0350dns.php

http://linux.vbird.org/linux_server/0350dns.php

也就是说,也有内容复制之嫌。

但是以“DNS 伺服器設定”为关键字检索site:linux.vbird.org有结果,而site:www.vbird.org却没有这篇文章的影子,只有这篇文章的老版本:http://www.vbird.org/linux_server/0350dns/0350dns.php存在,而且,这篇老文章被标记成了补充材料。

另外,另一篇文章(Enterprise Linux 实战讲座前言DNS 反解( Reverse Lookup )原理)的pdf文件:

http://linux.vbird.org/somepaper/20050630-dns-1.pdf分在了linux.vbird.org,

而同样文章的第二部分却分在了:www.vbird.org/somepaper/20050630-dns-2.pdf

但是他还不是照样很红火?

我想,是google根据判断把本来是一个站的内容分在了两个域名下。

说明这还是有问题的,我上vbird.org问一下站长vbird的想法如何?

也许,正如:SEO每日一帖的zac说的那样,我中了SEO的毒了?

如何分离个人信息,缓存动态页面(转帖)

下面是一个用于php中的静态缓存加入动态个人信息的方案,我觉得他的思路是可以借鉴的,就转帖在这里了。

正文

****************************************************************************

转自:(http://nio.infor96.com/archives/283

如何分离个人信息,缓存动态页面

肖理达 (KrazyNio AT hotmail.com), 2005.06.07, 转载请注明出处

一直想写一篇关于动态页面 cache 的文章,但每次?提笔?却又放弃,因为总是觉得准备得

还不够充分。今天埋头写下,只是希望对自己的工作做一些笔录。

1、问题起源

我们经常会在一个动态页面中加入很多个人信息,以 CMS 首页为例,用户登录之前显示登

录框,登录之后显示其用户名,并根据权限显示其可用模块的链接。由于每个用户登录之

后,显示出来的动态信息都是不一样的,所以这部分无法进行 cache,我们将这部分信息

定义为?个人信息?,它的特性是根据登录用户进行动态改变。

现在问题来了,就是一个 CMS 的首页,访问者的登录概率并不是百分百的,应该说有一大

部分人访问首页是没有登录的,这个时候的首页是一个公共的页面,没有任何个人信息,

或者说这时候首页的任何动态信息都是可以转换成静态的,也就是说这部分是可 cache 的

2、使用 JavaScript 分离个人信息

解决这个问题的方法有很多种,一种是将个人信息和其他信息进行分离,如在 CMS 首页中

加入一个外部的 JavaScript 文件,而这个文件的内容实际上是由 PHP 动态生成的。CMS

首页 index.php 代码片段:

<script language="JavaScript" src="/js/personal.php"></script>

?.

<script language=?JavaScript?>

document.write(sUser);

document.write(sLinks);

</script>

personal.php 代码片段:

<?php

session_start();

header(?Cache-Control: no-store, no-cache, must-revalidate?);

?>

sUser = ?<?php echo $_SESSION['USER']; ?>?;

sLinks = ?<?php echo addslashes($_SESSION['LINKS']); ?>?;

这种方法比较适合个人信息较少,易于集中显示的情况。通过 JavaScript 外挂代码实现

个人信息分离之后,personal.php 是永不 cache 的,这样也就可以放心地对 CMS 首页进

行 cache 了,具体的 cache 方法可采用 304 HTTP 头与 Cache_Lite 相结合的方式,这

在后边有详细代码示例。

3、选择性分离个人信息

一旦个人信息较多,很难对其进行分离的时候,上述方法实现起来就会比较麻烦了。接下

来介绍一种比较放宽的 cache 方式,就是只对用户未登录的 CMS 首页进行 cache,一旦

发现用户处于登录状态,则跳过 cache 部分,直接运行相关代码,我把这种方法称为?

选择性 cache
?。这种方法中,我们牺牲了一部分可 cache 的情况,但很大程度上提

高了个人信息的可扩充性,也就是说个人信息的多少、显示的位置等等都不再受到限制,

这是值得的,毕竟修改服务端代码要比修改大量的 JavaScript 代码要来得方便,而且

JavaScript 的调试也会比较麻烦。

分析一下这种 cache 方式,概要流程图如下:

image

代码片段如下:

<?php

session_cache_limiter(?must-revalidate?);

session_start();

if (empty($_SESSION['USER'])) { //未登录时才使用 cache

    ?.    //输出 cache

} else {

    //  直接输出页面内容,此条件下与未使用 cache 时一样

    $data =& get_data();

    echo $data;

}   //end if

?>

这里需要说明的一点是,由于 PHP 在使用 SESSION 时,php.ini 中默认设置的

session.cache_limiter 为 nocache,所以需要修改 cache_limiter,设置成

must-revalidate,使得客户端再次浏览当前页时必须发送相关 HTTP 头信息到服务器进行

验证,然后才决定是否加载客户端本地 cache。不要把客户端本地 cache 与服务器端

cache 搞混,之后的代码片段中会充分利用客户端 cache 和服务器端 cache 机制达到缓

存的目的。关于 must-revalidate,请参考 HTTP 规格说明书 RFC 2612 的 14.9.4 章节

上边的代码并不完整,接下来是更加深入的探讨客户端 cache 机制了,利用客户端 cache

,可以有效地减轻服务器端负载。首先了解一下 HTTP 头:Last-Modified 与

If-Modified-Since。简单的说,Last-Modified 与If-Modified-Since 都是用于记录页面

最后修改时间的 HTTP 头信息,只是 Last-Modified 是由服务器往客户端发送的 HTTP 头

,而 If-Modified-Since 则是由客户端往服务器发送的头,其工作原理图如下:

image

可以看到,再次请求本地存在的 cache 页面时,客户端会通过 If-Modified-Since 头将

先前服务器端发过来的 Last-Modified 最后修改时间戳发送回去,这是为了让服务器端进

行验证,通过这个时间戳判断客户端的页面是否是最新的,如果不是最新的,则返回新的

内容,如果是最新的,则返回 304 告诉客户端其本地 cache 的页面是最新的,于是客户

端就可以直接从本地加载页面了,这样在网络上传输的数据就会大大减少,同时也减轻了

服务器的负担。想要详细查看 HTTP 头信息,可以在 Firefox 中安装 LiveHTTPHeaders

插件,安装完成之后按 Alt+L 就可以在 Sidebar 中看到了。

现在再来完善之前的 index.php 代码:

<?php

session_cache_limiter(?must-revalidate?);

session_start();

function &get_data()

{

    //此函数用于获取本页面的输出内容

    //?.

}   //end function

if (empty($_SESSION['USER'])) { //未登录时才使用 cache

    //====================================================

    //  1. 检查 HTTP 头是否符合 304 的条件

    //====================================================

    //get_last_modified() 函数需要另外单独实现,此函数用于获取服务器端 cache 文件的最后修改时间,可将时间戳保存在数据库中。

    $last_modified = get_last_modified();

    $headers = getallheaders();

    if (strtotime($headers['If-Modified-Since']) == $last_modified) {

        //  返回 304 并结束程序运行

        header('HTTP/1.1 304 Not Modified');

        exit;

    }   //end if

    header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $last_modified) . ' GMT');

    //====================================================

    //  2. 检查 cache 文件是否存在

    //====================================================

    require_once 'Cache/Lite.php';

    //  参数设置

    $options = array(

        'cacheDir' => './cache/',

        'lifeTime' => 86400, //最大 cache 一天时间

        'fileNameProtection'   => false //使用 CMS 自身提供的 id 作为名字

    );

    $cache = new Cache_Lite($options);  //创建 Cache_Lite 对象

    $id = md5($_SERVER['REQUEST_URI']); //生成对应于 cache 文件的 ID

    if ($data = $cache->get($id)) {   //存在 cache 文件,获取内容,直接输出

        echo $data;

    } else {

        $data =& get_data();

        echo $data;

        flush();

        $cache->save($data);    //保存 cache

    }   //end if

} else {

    $data =& get_data();

    echo $data;

}   //end if

?>

测试时可以使用 LivHTTPHeaders 插件,你将会看到第一次访问时是返回 200,第二次到

第N次访问时则返回了 304,而登录之后,则一直都返回 200,因为我们选择性 cache 之

后,对登录之后一律运行程序输出,而不使用 cache,如果之后需要对输出的个人信息进

行修改,只需要改函数 get_data() 即可,也避免了 JavaScript 的调试。

总结

除此之外,还有其它方法可以实现分离个人信息,缓存动态页面的目的。而且为了提高服

务器运行效率,还可以使用数据库 cache、Squid 反向代理等,如 ADOdb 的 cache。目前

用的比较多的 Drupal 应用的就是本文中提到的第二种方法。

参考资料

HTTP Caching & Cache-Busting for Content Publishers

Hypertext Transfer Protocol ? HTTP/1.1

PHP Anthology, Volume 2: Applications. Chapter 5: Caching

Caching Tutorial for Web Authors and Webmasters

Drupal 源代码

Comments RSS | Trackback URL

4 Comments on ?关于 Cache(4)?

By zeal. June 13th, 2005 at 3:25 pm

我们目前采用的是oracle cache server以及squid。对于不能cache的内容采取分目录存放

。在代码设计的时候就考虑可cache性。对于大量需要用户交互的内容,似乎cache的作用

不大。

By Nio. June 13th, 2005 at 5:02 pm

嗯,如果内容本身全都是个人信息的话或者必须登录才能浏览的页面,就用不到这种cache

方法了,需要看登录与不登录的概率比而定 🙂

By nc. July 17th, 2006 at 12:43 pm

感谢你文章的提示,非常不错.

By ahu. October 8th, 2006 at 5:10 pm

zeal的公司貌似有些money~

**************************************************************************

                                                           转载完毕

另一段静态页面计数代码:


<script language="javascript" src="/data/include/count.php?id=$id"></

script>

转摘自:(http://www.mephp.com/view.php?tid=1&id=44