• 当人们还在浩叹第一次网络泡沫破灭的时候,互联网已经悄悄迎来了它的第二个春天;从某种意义上看,甚至已经进入了夏天——热烈但不乏浮躁、兴奋但失之肤浅。某位投资人声称今年总共有三十亿美金资本进入中国,言下之意,大家都可以甩开膀子大干快上,登陆纳市不好说,搞笔钱进来花差花差多半是没问题的。

    另一方面,程序员创业,在中国乃至国外,都不是什么新鲜事儿。我们是那么一群聪明、优秀的家伙,大脑发达,点子就像啤酒的泡沫,扑腾扑腾直往外冒,天生我才,有什么做不到的呢?遥想比尔盖茨当年,西装革履,谈笑间,多少豪杰灰飞烟灭……

    于是我看到,无数公司成立了,眼看他雄心勃勃,眼看他一败涂地。成败固然不足以论英雄,然而英雄却不得不面对可能的成败。可惜的是,程序员朋友们在创业的时候,往往没有做好充分准备。据一些资料显示,百分之七十五的新创公司,会在两、三年内倒闭。笔者也曾经见过许多程序员创业失败的个案;成功或不成功,有很多因素制约;对于立志创业的程序员,至少应该突破三关。

    第一是模式关。你的创业计划,也许起源于灵机一动。可惜的是,好点子并不能保证你创业成功。我相信多数程序员的点子,尚不至于低级到靠软色情、盗版、恶性SEO等等下作手段去骗取广告费的地步,但怎么从点子变成盈利模式,却是让很多创业者迷惑的事情。在一些业界聚会上,总听到类似“只要有流量,总有办法赚钱”之类的说法,在2000年持同样言论的创业者,多数已经成为失败的先烈,因为他们始终没明白,赚现钱的生意才是好生意。三大门户成功的要点,在于他们想出办法,把流量转化为盈利模式。缺乏有效的模式,流量只是成本。确定有效经营模式、组建有力创业团队,是首要任务。

    第二是管理关。从程序员变成管理者,是艰难的过程。你得明白两件事:一、管理和写程序一样,是门科学;二、人和计算机不一样,人有感情、会出错。协调沟通能力,是程序员创业必备的素质。曾经眼见一些项目经理,和手下技术人员通过邮件争辩不休,甚至发展到在Blog上互相嘲讽,这样的管理,可谓彻底失败。另一个极端是,和手下称兄道弟、一团和气,工作被感情所左右,酒肉害了朋友。管理有那么难吗?我看未必。只做对公司有利的事,就是根本原则。在和你的手下打交道时,请三思:我这么做,对公司有好处吗?对事业有好处吗?如果答案是否定的,那你需要另一个解决方案。

    第三是坚持关。一位多次创业不成功的朋友告诉我,他总结了一条“三年定律”,即任何事如果不能坚持三年,则一定失败。诚哉斯言!另一位朋友说,中国人相信机会,西方人相信方向和时间,虽有些偏激,却也不乏道理。许多程序员都属于思维活跃、点子特多的一类人,当有新鲜的想法出来时,他们倾向于放弃或冷落手上正在执行的计划。点子复点子,点子何其多,每天新点子,万事成蹉跎。西谚有云,双鸟在林不如一鸟在手;吃到嘴里的鸭子才是好鸭子,湖里那只鸭子看起来比较肥?也许吧,不过,吃了这只鸭子再去涉水抓那只,是不是更有把握呢?

    文短意深,未尽之处不及一一道来。奉上忠言数句,与程序员朋友们共勉:你永远不是最聪明的人;手下比你强是好事;创业不怕起步晚,只怕起个不停。

  • 一、LiveJournal发展历程

    LiveJournal是99年始于校园中的项目,几个人出于爱好做了这样一个应用,以实现以下功能:
    • 博客,论坛
    • 社会性网络,找到朋友
    • 聚合,把朋友的文章聚合在一起
    LiveJournal采用了大量的开源软件,甚至它本身也是一个开源软件。

    在上线后,LiveJournal实现了非常快速的增长:

    • 2004年4月份:280万注册用户。
    • 2005年4月份:680万注册用户。
    • 2005年8月份:790万注册用户。
    • 达到了每秒钟上千次的页面请求及处理。
    • 使用了大量MySQL服务器。
    • 使用了大量通用组件。

    二、LiveJournal架构现状概况

    livejournal_backend.png

    三、从LiveJournal发展中学习

    LiveJournal从1台服务器发展到100台服务器,这其中经历了无数的伤痛,但同时也摸索出了解决这些问题的方法,通过对LiveJournal的学习,可以让我们避免LJ曾经犯过的错误,并且从一开始就对系统进行良好的设计,以避免后期的痛苦。

    下面我们一步一步看LJ发展的脚步。

    1、一台服务器

    一台别人捐助的服务器,LJ最初就跑在上面,就像Google开始时候用的破服务器一样,值得我们尊敬。这个阶段,LJ的人以惊人的速度熟悉的Unix的操作管理,服务器性能出现过问题,不过还好,可以通过一些小修小改应付过去。在这个阶段里LJ把CGI升级到了FastCGI。

    最终问题出现了,网站越来越慢,已经无法通过优过化来解决的地步,需要更多的服务器,这时LJ开始提供付费服务,可能是想通过这些钱来购买新的服务器,以解决当时的困境。
    毫无疑问,当时LJ存在巨大的单点问题,所有的东西都在那台服务器的铁皮盒子里装着。

    LJ-backend-7.png

    2、两台服务器

    用付费服务赚来的钱LJ买了两台服务器:一台叫做Kenny的Dell 6U机器用于提供Web服务,一台叫做Cartman的Dell 6U服务器用于提供数据库服务。

    LJ-backend-8.png

    LJ有了更大的磁盘,更多的计算资源。但同时网络结构还是非常简单,每台机器两块网卡,Cartman通过内网为Kenny提供MySQL数据库服务。

    暂时解决了负载的问题,新的问题又出现了:

    • 原来的一个单点变成了两个单点。
    • 没有冷备份或热备份。
    • 网站速度慢的问题又开始出现了,没办法,增长太快了。
    • Web服务器上CPU达到上限,需要更多的Web服务器。

    3、四台服务器

    又买了两台,Kyle和Stan,这次都是1U的,都用于提供Web服务。目前LJ一共有3台Web服务器和一台数据库服务器。这时需要在3台Web服务器上进行负载均横。

    LJ-backend-9.png

    LJ把Kenny用于外部的网关,使用mod_backhand进行负载均横。

    然后问题又出现了:

    • 单点故障。数据库和用于做网关的Web服务器都是单点,一旦任何一台机器出现问题将导致所有服务不可用。虽然用于做网关的Web服务器可以通过保持心跳同步迅速切换,但还是无法解决数据库的单点,LJ当时也没做这个。
    • 网站又变慢了,这次是因为IO和数据库的问题,问题是怎么往应用里面添加数据库呢?

    4、五台服务器

    又买了一台数据库服务器。在两台数据库服务器上使用了数据库同步(Mysql支持的Master-Slave模式),写操作全部针对主数据库(通过Binlog,主服务器上的写操作可以迅速同步到从服务器上),读操作在两个数据库上同时进行(也算是负载均横的一种吧)。

    LJ-backend-10.png

    实现同步时要注意几个事项:

    • 读操作数据库选择算法处理,要选一个当前负载轻一点的数据库。
    • 在从数据库服务器上只能进行读操作
    • 准备好应对同步过程中的延迟,处理不好可能会导致数据库同步的中断。只需要对写操作进行判断即可,读操作不存在同步问题。

    5、更多服务器

    有钱了,当然要多买些服务器。部署后快了没多久,又开始慢了。这次有更多的Web服务器,更多的数据库服务器,存在 IO与CPU争用。于是采用了BIG-IP作为负载均衡解决方案。

    LJ-backend-11.png

    6、现在我们在哪里:

    LJ-backend-1.png

    现在服务器基本上够了,但性能还是有问题,原因出在架构上。

    数据库的架构是最大的问题。由于增加的数据库都是以Slave模式添加到应用内,这样唯一的好处就是将读操作分布到了多台机器,但这样带来的后果就是写操作被大量分发,每台机器都要执行,服务器越多,浪费就越大,随着写操作的增加,用于服务读操作的资源越来越少。

    LJ-backend-2.png

    由一台分布到两台

    LJ-backend-3.png

    最终效果

    现在我们发现,我们并不需要把这些数据在如此多的服务器上都保留一份。服务器上已经做了RAID,数据库也进行了备份,这么多的备份完全是对资源的浪费,属于冗余极端过度。那为什么不把数据分布存储呢?

    问题发现了,开始考虑如何解决。现在要做的就是把不同用户的数据分布到不同的服务器上进行存储,以实现数据的分布式存储,让每台机器只为相对固定的用户服务,以实现平行的架构和良好的可扩展性。

    为了实现用户分组,我们需要为每一个用户分配一个组标记,用于标记此用户的数据存放在哪一组数据库服务器中。每组数据库由一个master及几个slave组成,并且slave的数量在2-3台,以实现系统资源的最合理分配,既保证数据读操作分布,又避免数据过度冗余以及同步操作对系统资源的过度消耗。

    LJ-backend-4.png

    由一台(一组)中心服务器提供用户分组控制。所有用户的分组信息都存储在这台机器上,所有针对用户的操作需要先查询这台机器得到用户的组号,然后再到相应的数据库组中获取数据。

    这样的用户架构与目前LJ的架构已经很相像了。

    在具体的实现时需要注意几个问题:

    • 在数据库组内不要使用自增ID,以便于以后在数据库组之间迁移用户,以实现更合理的I/O,磁盘空间及负载分布。
    • 将userid,postid存储在全局服务器上,可以使用自增,数据库组中的相应值必须以全局服务器上的值为准。全局服务器上使用事务型数据库InnoDB。
    • 在数据库组之间迁移用户时要万分小心,当迁移时用户不能有写操作。

    7、现在我们在哪里

    LJ-backend-5.png

    问题:

    • 一个全局主服务器,挂掉的话所有用户注册及写操作就挂掉。
    • 每个数据库组一个主服务器,挂掉的话这组用户的写操作就挂掉。
    • 数据库组从服务器挂掉的话会导致其它服务器负载过大。
    • 对于Master-Slave模式的单点问题,LJ采取了Master-Master模式来解决。所谓Master-Master实际上是人工实现的,并不是由MySQL直接提供的,实际上也就是两台机器同时是Master,也同时是Slave,互相同步。

    Master-Master实现时需要注意:

    • 一个Master出错后恢复同步,最好由服务器自动完成。
    • 数字分配,由于同时在两台机器上写,有些ID可能会冲突。

    解决方案:

    • 奇偶数分配ID,一台机器上写奇数,一台机器上写偶数
    • 通过全局服务器进行分配(LJ采用的做法)。

    Master-Master模式还有一种用法,这种方法与前一种相比,仍然保持两台机器的同步,但只有一台机器提供服务(读和写),在每天晚上的时候进行轮换,或者出现问题的时候进行切换。

    8、现在我们在哪里

    LJ-backend-6.png

    现在插播一条广告,MyISAM VS InnoDB。

    使用InnoDB:

    • 支持事务
    • 需要做更多的配置,不过值得,可以更安全的存储数据,以及得到更快的速度。

    使用MyISAM:

    • 记录日志(LJ用它来记网络访问日志)
    • 存储只读静态数据,足够快。
    • 并发性很差,无法同时读写数据(添加数据可以)
    • MySQL非正常关闭或死机时会导致索引错误,需要使用myisamchk修复,而且当访问量大时出现非常频繁。

    9、缓存

    去年我写过一篇文章介绍memcached,它就是由LJ的团队开发的一款缓存工具,以key-value的方式将数据存储到分布的内存中。LJ缓存的数据:

    • 12台独立服务器(不是捐赚的)
    • 28个实例
    • 30GB总容量
    • 90-93%的命中率(用过squid的人可能知道,squid内存加磁盘的命中率大概在70-80%)

    如何建立缓存策略?

    想缓存所有的东西?那是不可能的,我们只需要缓存已经或者可能导致系统瓶颈的地方,最大程度的提交系统运行效率。通过对MySQL的日志的分析我们可以找到缓存的对象。

    缓存的缺点?

    • 没有完美的事物,缓存也有缺点:
    • 增大开发量,需要针对缓存处理编写特殊的代码。
    • 管理难度增加,需要更多人参与系统维护。
    • 当然大内存也需要钱。

    10、Web访问负载均衡

    在数据包级别使用BIG-IP,但BIG-IP并不知道我们内部的处理机制,无法判断由哪台服务器对这些请求进行处理。反向代理并不能很好的起到作用,不是已经够快了,就是达不到我们想要的效果。

    所以,LJ又开发了Perlbal。特点:

    • 快,小,可管理的http web 服务器/代理
    • 可以在内部进行转发
    • 使用Perl开发
    • 单线程,异步,基于事件,使用epoll , kqueue
    • 支持Console管理与http远程管理,支持动态配置加载
    • 多种模式:web服务器,反向代理,插件
    • 支持插件:GIF/PNG互换?

    11、MogileFS

    LJ使用开源的MogileFS作为分布式文件存储系统。MogileFS使用非常简单,它的主要设计思想是:

    • 文件属于类(类是最小的复制单位)
    • 跟踪文件存储位置
    • 在不同主机上存储
    • 使用MySQL集群统一存储分布信息
    • 大容易廉价磁盘

    到目前为止就这么多了,更多文档可以在http://www.danga.com/words/找到。Danga.comLiveJournal.com的同学们拿这个文档参加了两次MySQL Con,两次OS Con,以及众多的其它会议,无私的把他们的经验分享出来,值得我们学习。在web2.0时代快速开发得到大家越来越多的重视,但良好的设计仍是每一个应用的基础,希望web2.0们在成长为Top500网站的路上,不要因为架构阻碍了网站的发展。

    参考资料:http://www.danga.com/words/2005_oscon/oscon-2005.pdf

  • 2006-03-15

    Apache学习笔记

    作者: 车东 Email: chedongATbigfoot.com/chedongATchedong.com

    写于:2002/07 最后更新: 06/26/2004 23:42:36

    版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
    http://www.chedong.com/tech/apache_install.html

    关键词: apache install php resin mod_gzip mod_expire webalizer cronolog

    内容摘要:

    Apache是一个历史悠久并且功能十分强大的WEB服务器,但其丰富的功能对于一个新手来说往往不知道从何下手。我个人感觉Apache的设计充分体现了模块化设计的优势,通过在动态模块加载(DSO)模式下的安装,任何子应用模块都可以通过配置文件的简单修改进行插拔式的灵活配置。然后我们就可以从简单的静态html服务开始,一个模块一个模块的学习使用。从单纯的HTML静态服务(core),到复杂的动态页面服务(core + php, core + resin, core + php + mod_gzip, core + resin + mod_expire)。

    本文主要从简化安装==>性能调优==>维护方便的角度,介绍了WEB服务的规划、HTTPD安装/应用模块配置、升级/维护等过程。让Apache和PHP,Resin等应用模块的独立升级,完全互不影响。

    1. WEB应用容量规划:根据硬件配置和WEB应用的特点进行WEB服务的规划及一些简单的估算公式;
    2. Apache安装过程:apache的通用的简化安装选项,方便以后的应用的模块化配置;
      修改 HARD_SERVER_LIMIT:
      vi /path/to/apache_src/src/include/httpd.h
      #define HARD_SERVER_LIMIT 2560 <===将原来的 HARD_SERVER_LIMIT 256 后面加个“0”
      apache编译:
      ./configure --prefix=/home/apache --enable-shared=max --enable-module=most
    3. 可选应用模块/工具的安装:php resin mod_gzip mod_expire及各个模块之间的配合;
      mod_php安装:./configure --with-apxs=/home/apache/bin/apxs --enable-track-vars --with-mysql
      mod_resin安装:./configure --with-apxs=/home/apache/bin/apxs
      mod_gzip安装:/home/apache/bin/apxs -i -a -c mod_gzip.c
      工具:日志轮循工具cronolog安装:http://www.cronolog.org
    4. 升级/维护:看看通用和模块化的安装过程如何简化了日常的升级/维护工作;
      按照以上的方法:系统管理员和应用管理员的职责可以清楚的分开,互相独立。
      系统安装:系统管理员的职责就是安装好一台DSO模式的Apache,然后COLON即可,
      应用安装:由应用管理员负责具体应用所需要的模块,比如PHP Resin等,并设置httpd.conf中相关的配置。
      系统升级:系统管理员:升级操作系统/升级Apache
      应用升级:应用管理员:升级应用模块,PHP Resin等。

    WEB应用的容量规划

    Apache主要是一个内存消耗型的服务应用,我个人总结的经验公式:
    apache_max_process_with_good_perfermance < (total_hardware_memory / apache_memory_per_process ) * 2
    apache_max_process = apache_max_process_with_good_perfermance * 1.5

    为什么会有一个apache_max_process_with_good_perfermance和apache_max_process呢?原因是在低负载下系统可以使用更多的内存用于文件系统的缓存,从而进一步提高单个请求的响应速度。在高负载下,系统的单个请求响应速度会慢不少,而超过apache_max_process,系统会因为开始使用硬盘做虚拟内存交换空间而导致系统效率急剧下降。此外,同样的服务:2G内存的机器的apache_max_process一般只设置到1G内存的1.7倍,因为Apache本身会因为进程过多导致性能下降。

    例子1:
    一个apache + mod_php的服务器:一个apache进程一般需要4M内存
    因此在一个1G内存的机器上:apache_max_process_with_good_perfermance < (1g / 4m) * 2 = 500
    apache_max_process = 500 * 1.5 = 750
    所以规划你的应用让服务尽量跑在500个进程以下以保持比较高的效率,并设置Apache的软上限在800个。

    例子2:
    一个apache + mod_resin的服务器: 一个apache进程一般需要2M内存
    在一个2G内存的机器上:
    apache_max_process_with_good_perfermance < (2g / 2m ) * 2 = 2000
    apache_max_process = 2000 * 1.5 = 3000

    以上估算都是按小文件服务估算的(一个请求一般大小在20k以下)。对于文件下载类型站点,可能还会受其他因素:比如带宽等的影响。

    Apache安装过程

    服务器个数的硬上限HARD_SERVER_LIMIT的修改:
    在Apache的源代码中缺省的最大进程数是256个,需要修改apache_1.3.xx/src/include/httpd.h
    #ifndef HARD_SERVER_LIMIT
    #ifdef WIN32
    #define HARD_SERVER_LIMIT 1024
    #elif defined(NETWARE)
    #define HARD_SERVER_LIMIT 2048
    #else
    #define HARD_SERVER_LIMIT 2560 <===将原来的HARD_SERVER_LIMIT 256 后面加个“0”
    #endif
    #endif

    解释:
    Apache缺省的最大用户数是256个:这个配置对于服务器内存还是256M左右的时代是一个非常好的缺省设置,但随着内存成本的急剧下降,现在大型站点的服务器内存配置一般比当时要高一个数量级不止。所以256个进程的硬限制对于一台1G内存的机器来说是太浪费了,而且Apache的软上限max_client是受限于HARD_SERVER_LIMIT的,因此如果WEB服务器内存大于256M,都应该调高Apache的HARD_SERVER_LIMIT。根据个人的经验:2560已经可以满足大部分小于2G内存的服务器的容量规划了(Apache的软上限的规划请看后面)。

    Apache的编译:以下通用的编译选项能满足以后任意模块的安装
    ./configure --prefix=/another_driver/apache/ --enable-shared=max --enable-module=most
    比如:
    ./configure --prefix=/home/apache/ --enable-shared=max --enable-module=most

    解释:
    --prefix=/another_driver/apache/:建议将apache服务安装在另外一个驱动设备上的目的在于硬盘往往是一个系统使用寿命最低的设备,因此:将服务数据和系统完全分开,不仅能提高了数据的访问速度,更重要的,大大方便系统升级,应用备份和恢复过程。

    --shared-module=max:使用动态加载方式载入子模块会带来5%的性能下降,但和带来的配置方便相比更本不算什么:比如模块升级方便,系统升级风险降低,安装过程标准化等

    --enable-module=most:用most可以将一些不常用的module编译进来,比如后面讲到的mod_expire是就不在apache的缺省常用模块中

    如果不想build so, 也可以这样:
    ./configure \
    "--with-layout=Apache" \
    "--prefix=/path/to/apache" \
    "--disable-module=access" \
    "--disable-module=actions" \
    "--disable-module=autoindex" \
    "--disable-module=env" \
    "--disable-module=imap" \
    "--disable-module=negotiation" \
    "--disable-module=setenvif" \
    "--disable-module=status" \
    "--disable-module=userdir" \
    "--disable-module=cgi" \
    "--disable-module=include" \
    "--disable-module=auth" \
    "--disable-module=asis"

    但结果会发现,这样编译对服务性能只能有微小的提高(5%左右),但却失去了以后系统升级和模块升级的灵活性,无论是模块还是Apache本身升级都必须把Apache和PHP的SOURCE加在一起重新编译。

    apache的缺省配置文件一般比较大:可以使用去掉注释的方法精简一下:然后再进入具体的培植过程能让你更快的定制出你所需要的。
    grep -v "#" httpd.conf.default >httpd.conf

    需要修改的通用项目有以下几个:

    #服务端口,缺省是8080,建议将整个Apache配置调整好后再将服务端口改到正式服务的端口
    Port 8080 => 80

    #服务器名:缺省没有
    ServerName name.example.com

    #最大服务进程数:根据服务容量预测设置
    MaxClients 256 => 800

    #缺省启动服务后的服务进程数:等服务比较平稳后,按平均负载下的httpd个数设置就可以
    StartServers 5 => 200

    不要修改:
    以前有建议说修改:
    MinSpareServers 5 => 100
    MaxSpareServers 10 => 200

    但从我的经验看来:缺省值已经是非常优化的了,而且让Apache自己调整子共享进程个数还是比较好的。

    特别修改:
    在solaris或一些比较容易出现内存泄露的应用上:
    MaxRequestsPerChild 0 =>3000

    应用模块和工具的安装配置:

    由于使用模块动态加载的模式,所以可以方便的通过简单的配置调整来把Apache定制成你需要的:最好把不常用模块全部清除(无论处于安全还是效率)。
    比如:对于静态页面服务器:就什么其他子模块都不加载,对于PHP应用就加上PHP模块,对于JAVA应用就把Resin模块加载上。而且各种模块的插拔非常简单,这样调试过程中就可以简单的通过注释掉不需要的模块,而不用重新编译。

    一般说来,可以不需要的模块包括:
    #LoadModule env_module libexec/mod_env.so
    #LoadModule negotiation_module libexec/mod_negotiation.so
    #LoadModule status_module libexec/mod_status.so
    #server side include已经过时了
    #LoadModule includes_module libexec/mod_include.so
    #不需要将没有缺省index文件的目录下所有文件列出
    #LoadModule autoindex_module libexec/mod_autoindex.so
    #尽量不使用CGI:一直是Apache安全问题最多的地方
    #LoadModule cgi_module libexec/mod_cgi.so
    #LoadModule asis_module libexec/mod_asis.so
    #LoadModule imap_module libexec/mod_imap.so
    #LoadModule action_module libexec/mod_actions.so
    #不使用安全认证可以大大提高访问速度
    #LoadModule access_module libexec/mod_access.so
    #LoadModule auth_module libexec/mod_auth.so
    #LoadModule setenvif_module libexec/mod_setenvif.so

    最好保留的有:
    #用于定制log格式
    LoadModule config_log_module libexec/mod_log_config.so
    #用于增加文件应用的关联
    LoadModule mime_module libexec/mod_mime.so
    #用于缺省index文件:index.php等
    LoadModule dir_module libexec/mod_dir.so

    可用可不用的有:
    #比如:需要在~/username/下调试php可以将
    LoadModule userdir_module libexec/mod_userdir.so
    #比如:需要将以前的URL进行转向或者需要使用CGI script-alias
    LoadModule alias_module libexec/mod_alias.so

    常用的模块:
    最常用的可能就是php和JAVA应用服务器的前端,此外,从性能上讲利用mod_gzip可以减少40%左右的流量,减少机器用于传输的负载,而mod_expires可以减少10%左右的重复请求,让重复的用户对指定的页面请求结果都CACHE在本地,根本不向服务器发出请求。

    建议将所有MODULE的配置都放到相应模块的配置内部:some_module config

    PHP的安装:
    /path/to/php_src/configure --with-apxs=/path/to/apache/bin/apxs --with-other-modules-you-need
    需要修改的配置:
    AddType application/x-httpd-php .php .php3 .any_file_in_php

    resin的安装设置:
    /path/to/resin/src/configure --with-apxs=/path/to/apache/bin/apxs

    具体的resin设置放在另外一个文件中:比如/home/resin/conf/resin.conf

    CauchoConfigFile /path/to/apache/conf/resin.conf

    mod_expires的安装配置:

        ExpiresActive on
        ExpiresByType image/gif "access plus 1 month"
        ExpiresByType text/css "now plus 1 month"
        ExpiresDefault "now plus 1 day"

    注释:
    所有的.gif文件1个月以后过期
    所有的文件缺省1天以后过期

    mod_gzip的安装:
    /path/to/apache/bin/apxs -i -a -c mod_gzip.c

    配置:mod_gzip+mod_php
    LoadModule gzip_module modules/mod_gzip.so

    ...
    AddModule mod_gzip.c

    ...

    mod_gzip_on Yes
    mod_gzip_minimum_file_size 1000
    mod_gzip_maximum_file_size 300000
    mod_gzip_item_include file \.htm$
    mod_gzip_item_include file \.html$
    mod_gzip_item_include file \.php$
    mod_gzip_item_include file \.php3$
    mod_gzip_item_include mime text/.*
    mod_gzip_item_include mime httpd/unix-directory
    #mod_gzip的临时工作目录
    mod_gzip_temp_dir /tmp/mod_gzip
    mod_gzip_dechunk Yes
    mod_gzip_keep_workfiles No

    mod_gzip和mod_php的配合:不要让mod_gzip和mod_php使用同一个临时目录,php_session存放目录可以通过php.ini设置到session.save_path = /tmp/php_sess

    mod_gzip和Resin配合:要让mod_gzip在mod_caucho后加载,否则mod_gzip不起作用
    ...othr modules
    AddModule mod_so.c
    AddModule mod_caucho.c
    #notice: mod_gzip must load after mod_caucho
    AddModule mod_gzip.c
    AddModule mod_expires.c
    ...

    配置:mod_gzip + resin

    mod_gzip_on Yes
    mod_gzip_dechunk yes
    mod_gzip_keep_workfiles No
    mod_gzip_minimum_file_size 3000
    mod_gzip_maximum_file_size 300000
    mod_gzip_item_include file \.html$
    mod_gzip_item_include mime text/.*
    mod_gzip_item_include mime httpd/unix-directory
    mod_gzip_item_include handler 'caucho-request'

    日志的轮循:cronolog的安装和设置
    cronolog可以非常整齐的将日志按天轮循存储
    缺省编译安装到/usr/local/bin/下,只需要将配置改成:

    CustomLog "|/usr/local/sbin/cronolog /home/apache/logs/%w/access_log" combined

    日志将按天截断并存放在以星期为目录名的目录下:比如:log/1是周一,log/5是周五, log/0是周日

    用gzip压缩每天的日志:
    30 4 * * * /usr/bin/gzip -f /home/apache/logs/`date -d yesterday +%w`/access_log

    日志的定期删除:
    30 5 * * */usr/bin/find /home/apache/logs/ -name access_log.gz -mtime +3 |xargs -r /bin/rm -f

    升级维护

    由于使用动态模块加载方式(DSO模式)安装Apache,Apache的HTTPD核心服务和应用模块以及应用模块之间都变的非常灵活,建议将所有独立模块的配置都放在

    CONFIGURATIONS..

    里,这样配置非常容易通过屏蔽某个模块来进行功能调整:比如:
    #AddModule mod_gzip.c
    就屏蔽了mod_gzip,而其他模块不首任何影响。

    安装和维护过程:

    • 系统安装:系统管理员的职责就是安装系统和一个按照DSO模式安装的Apache,然后COLON。
    • 应用安装:由应用管理员负责具体应用所需要的模块并设置HTTPD。
    • 系统升级:系统管理员:升级系统/升级Apache
    • 应用升级:应用管理员:升级应用模块:PHP CAUCHO等
    • 系统备份/恢复:如果Apache不在缺省的系统盘上,只需要将Apache目录备份就可以了,遇到系统分区的硬件问题直接使用预先准备好的系统COLON,再直接将Apache所在物理盘恢复就行了。
    系统管理员:Apache的最简化安装OS + Apache (httpd core only)
    应用管理员:应用模块定制纯静态页面服务
    core
    PHP动态页面
    core+so
    +php
    JAVA应用
    core+so
    +caucho
    +ssl
    应用例子:www.example.com
    image.example.com
    bbs.example.commall.example.com

    例子:Apache和PHP模块的独立升级。

    如果Apache是按照以下方式安装:
    ./configure --prefix=/home/apache --enable-shared=max --enable-module=most
    PHP是按照以下方式安装:
    ./configure --with-apxs=/home/apache/bin/apxs --enable-track-vars --with-mysql

    以后单独升级Apache的时候,仍然是:
    ./configure --prefix=/home/apache --enable-shared=max --enable-module=most
    make
    su
    #/home/apache/bin/apachectl stop
    #make install

    单独升级php时,仍然是:
    ./configure --with-apxs=/home/apache/bin/apxs --enable-track-vars --with-mysql
    make
    su
    #/home/apache/bin/apachectl stop
    #make install

  • 第3章 编译和安装

    3.1 安装之前

    假如你使用unix 有一段时间,并且已编译过许多其他软件包,那么只需快速的扫描本章。编译安装squid 的过程与安装其他软件相似。

    为了编译squid,你需要一个ANSI C 编译器。不要被ANSI 字眼吓倒。假如你已经有一个编译器,它顺从ANSI 指令,那么也一样。GNU C 编译器(gcc)是很好的选择,它被广泛使用。大部分操作系统在其标准安装中附带了C 编译器,不过Solaris 和HP-UX 除外。假如你使用这样的操作系统,那可能没有安装编译器。

    理论上你应该在即将运行squid 的机器上编译squid。安装过程侦察你的操作系统以发现特定的参数,例如可用文件描述符的数量。然而,假如你的系统没有C 编译器存在,你也许会在其他机器上编译squid,然后把二进制代码copy 回来。如果操作系统不同,那么squid可能会遇到问题。假如操作系统有不同的内核配置,squid 会变得混乱。

    除了C 编译器,你还需要perl 和awk。awk 是所有unix 系统的标准程序,所以你不必担心它。perl 也是相当普及的,但它也许没有默认安装在你的系统上。你需要gzip 程序来解压源代码发布文件。

    对Solaris 用户,请确认/usr/ccs/bin 包含在你的PATH 环境变量里,即使你使用gcc编译器。为了编译squid,make 和ar 程序需要在这个目录找到。

    3.2 解开源代码包

    在下载完源代码后,你需要在某个目录解开它。具体哪个目录无关紧要。你能解开squid在你的家目录或任何其他地方,大概需要20M 的自由磁盘空间。我个人喜欢用/tmp。使用tar 命令来展开源代码目录:
    % cd /tmp
    % tar xzvf /some/where/squid-2.5.STABLE4-src.tar.gz

    一些tar 程序不支持z选项,该选项自动解压gzip 文件。如果这样,你需要运行如下命令:
    % gzip -dc /some/where/squid-2.5.STABLE4-src.tar.gz | tar xvf -

    一旦源代码被展开,下一步通常是配置源代码树。然而,假如这是你第一次编译squid,你应确认特定的内核资源限制足够高。怎样发现,请继续。

    3.3 调整内核

    Squid 在高负载下,需要大量的内核资源。特别的,你需要给你的系统配置比正常情况更高的文件描述符和缓存。文件描述符的限制通常很恼人。你最好在开始编译squid 之前来增加这些限制的大小。

    因为这点,你可能为了避免重建内核的麻烦,而倾向于使用预编译的二进制版本。不幸的是,不管如何你必须重建一个新内核。squid 和内核通过数据结构来交换信息,数据结构的大小不能超过设置的文件描述符的限制。squid 在运行时检查这些设置,并且使用最安全的(最小的)值。这样,即使预编译的二进制版本有比你的内核更高的文件描述符,但还是以你系统内核的实际数值为主。

    为了改编一些参数,你需要重建新内核。这个过程在不同的操作系统之间不同。假如需要,请参阅Unix 系统管理员手册(Prentice Hall 出版)或者你的操作系统文档。假如你正使用Linux,可能不必重建内核。

    3.3.1 文件描述符

    文件描述符是一个简单的整数,用以标明每一个被进程所打开的文件和socket。第一个打开的文件是0,第二个是1,依此类推。Unix 操作系统通常给每个进程能打开的文件数量强加一个限制。更甚的是,unix 通常有一个系统级的限制。

    因为squid 的工作方式,文件描述符的限制可能会极大的影响性能。当squid 用完所有的文件描述符后,它不能接收用户新的连接。也就是说,用完文件描述符导致拒绝服务。直到一部分当前请求完成,相应的文件和socket 被关闭,squid 不能接收新请求。当squid发现文件描述符短缺时,它会发布警告。

    在运行./configure 之前,检查你的系统的文件描述符限制是否合适,能给你避免一些麻烦。大多数情况下,1024 个文件描述符足够了。非常忙的cache可能需要4096或更多。在配置文件描述符限制时,我推荐设置系统级限制的数量为每个进程限制的2 倍。

    通常在你的Unix shell 中能找到系统的文件描述符限制。所有的C shell 及其类似的shell有内建的limit 命令。更新的Bourne shell 及其类似的shell 有一条叫做ulimit 的命令。为了发现你的系统的文件描述符限制,试运行如下命令:
    csh% limit descriptors unlimited
    csh% limit descriptors
    descriptors 4096

    或者

    sh$ ulimit -n unlimited
    sh$ ulimit -n
    4096

    在Freebsd 上,你能使用sysctl 命令:
    % sysctl -a | grep maxfiles
    kern.maxfiles: 8192
    kern.maxfilesperproc: 4096

    如果你不能确认文件描述符限制,squid 的./configure 脚本能替你做到。当你运行./configure 时,请见3.4 章节,观察末尾这样的输出:
    checking Maximum number of file descriptors we can open... 4096

    假如其他的limit,ulimit,或者./configure 报告这个值少于1024,你不得不在编译squid 之前,花费时间来增加这个限制值的大小。否则,squid 在高负载时执行性能将很低。

    增加文件描述符限制的方法因系统不同而不同。下面的章节提供一些方法帮助你开始。

    3.3.1.1 Freebsd,NetBSD,OpenBSD

    编辑你的内核配置文件,增加如下一行:
    options MAXFILES=8192

    在OpenBSD 上,使用option 代替options。然后,configure,编译,和安装新内核。最后重启系统以使内核生效。

    3.3.1.2 Linux

    在Linux 上配置文件描述符有点复杂。在编译squid 之前,你必须编辑系统include 文件中的一个,然后执行一些shell 命令。请首先编辑/usr/include/bits/types.h 文件,改变__FD_SETSIZE 的值:
    #define _ _FD_SETSIZE 8192

    下一步,使用这个命令增加内核文件描述符的限制:
    # echo 8192 >; /proc/sys/fs/file-max

    最后,增加进程文件描述符的限制,在你即将编译squid 的同一个shell 里执行:
    sh# ulimit -Hn 8192

    该命令必须以root 运行,仅仅运行在bash shell。不必重启机器。

    使用这个技术,你必须在每一次系统启动后执行上述echo 和ulimit 命令,或者至少在squid 启动之前。假如你使用某个rc.d 脚本来启动squid,那是一个放置这些命令的好地方。

    3.3.1.3 Solaris

    增加该行到你的/etc/system 文件:
    set rlim_fd_max = 4096

    然后,重启机器以使改动生效。

    3.3.2 Mbuf Clusters

    BSD 基础的网络代码使用一个叫做mbuf(参阅W.R.Stevens 的TCP/IP 描述卷2)的数据结构。Mbuf 典型的是小块内存(例如128 字节)。较大的网络包的数据存储在mbuf clusters里。内核可能给系统可用的mbuf clusters 的总数量强加一个最高限制。你能使用netstat 命令来发现这个限制:
    % netstat -m
    196/6368/32768 mbufs in use (current/peak/max):
    146 mbufs allocated to data
    50 mbufs allocated to packet headers
    103/6182/8192 mbuf clusters in use (current/peak/max)
    13956 Kbytes allocated to network (56% of mb_map in use)
    0 requests for memory denied
    0 requests for memory delayed
    0 calls to protocol drain routines

    在这个例子里,有8192 个mbuf clusters 可用,但是永远不会同时用到6182 个。当系统用尽mbuf clusters 时,I/O 机制例如read()和write()返回“无缓存空间可用”的错误信息。

    NetBSD 和OpenBSD 使用netstat -m 不会显示mbuf 的输出。代替的,它们在syslog 里报告:"WARNING: mclpool limit reached" 。

    为了增加mbuf clusters 的数量,你必须在内核配置文件里增加一个选项:
    options NMBCLUSTERS=16384
    Squid 中文权威指南 3

    3.3.3 临时端口范围

    临时端口是TCP/IP 栈分配给出去连接的本地端口。换句话说,当squid 发起一条连接到另一台服务器,内核给本地socket 分配一个端口号。这些本地端口号有特定的范围限制。

    例如,在FreeBSD 上,默认的临时端口范围是1024-5000。

    临时端口号的短缺对非常忙的代理服务器(例如每秒数百个连接)来说,会较大的影响性能。这是因为一些TCP 连接在它们被关闭时进入TIME_WAIT 状态。当连接进入TIME_WATI 状态时,临时端口号不能被重用。

    你能使用netstat 命令来显示有多少个连接进入这个状态:

    % netstat -n | grep TIME_WAIT
    Proto Recv-Q Send-Q Local Address Foreign Address (state)
    tcp4 0 0 192.43.244.42.19583 212.67.202.80.80 TIME_WAIT
    tcp4 0 0 192.43.244.42.19597 202.158.66.190.80 TIME_WAIT
    tcp4 0 0 192.43.244.42.19600 207.99.19.230.80 TIME_WAIT
    tcp4 0 0 192.43.244.42.19601 216.131.72.121.80 TIME_WAIT
    tcp4 0 0 192.43.244.42.19602 209.61.183.115.80 TIME_WAIT
    tcp4 0 0 192.43.244.42.3128 128.109.131.47.25666 TIME_WAIT
    tcp4 0 0 192.43.244.42.3128 128.109.131.47.25795 TIME_WAIT
    tcp4 0 0 192.43.244.42.3128 128.182.72.190.1488 TIME_WAIT
    tcp4 0 0 192.43.244.42.3128 128.182.72.190.2194 TIME_WAIT

    注意这个例子中既有客户端连接又有服务器端的连接。客户端连接有3128作为临时端口号,服务器端连接有80作为远程主机的端口号。临时端口号出现在本地地址栏里。在该例子里,它们是19000 秒。

    如果你没有看到数千个临时端口在TIME_WAIT状态,那也许不必增加这个端口范围。

    在Freebsd 上,用如下命令增加临时端口范围:
    # sysctl -w net.inet.ip.portrange.last=30000

    在OpenBSD 上,命令类似,但sysctl 变量有不同的名字:
    # sysctl -w net.inet.ip.portlast=49151

    在NetBSD 上,事情稍有不同。默认的值是49152-65535.为了增加这个范围,需改变最低限制:
    # sysctl -w net.inet.ip.anonportmin=10000

    在Linux 上,简单的写一对数字到下列指定文件:
    # echo "1024 40000" >; /proc/sys/net/ipv4/ip_local_port_range

    不要忘记将这些命令加到你的系统启动脚本中,以使机器每一次重启后都生效。

    3.4 Configure 脚本

    象许多其他Unix 软件一样,squid在开始编译之前使用./configure脚本来了解操作系统信息。./configure脚本由流行的GNU autoconf程序产生。当script运行时,它用不同的方法来侦察系统,以发现关于库,函数,类型,参数,和有没有功能被提供等。./configure所做的第一件事情是去找一个C 编译器。假如C编译器没有找到,或者编译一个简单的测试程序失败,./configure脚本不能继续。

    ./configure 脚本有大量的选项。最重要的是安装prefix。在运行./configure 之前,你需要决定squid 被安装在哪里。prefix选项指定squid日志,二进制文件,和配置文件的默认位置。你可以在安装之后改变这些文件的位置,但假如你现在决定,事情更容易。

    默认的安装位置是/usr/local/squid.squid将文件放在prefix 指定目录下面的7 个子目录:

    % ls -l /usr/local/squid
    total 5
    drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 bin
    drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 etc
    drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 libexec
    drwxr-x--- 3 wessels wheel 512 Apr 28 20:43 man
    drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 sbin
    drwxr-x--- 4 wessels wheel 512 Apr 28 20:42 share
    drwxr-x--- 4 wessels wheel 512 Apr 28 20:43 var

    Squid 使用bin,etc,libexec,man,sbin,和share 目录存放一些相对较小的文件(或其他目录),这些文件不经常改变。但var目录的文件别有洞天。这里你可以发现squid 的日志文件,它增长得非常大(数十或数百兆)。var 也是实际磁盘cache 的默认位置。你也许想将var 目录放在磁盘空间足够的位置,这样做较容易的方法是使用--localstatedir 选项:
    % ./configure --localstatedir=/bigdisk/var

    当配置squid 时,你不必对这些路径名称担心太多。你以后可以在squid.conf文件里改变这些路径名。

    3.4.1 configure 选项

    ./configure 脚本有大量的不同选项,它们以-开始。当你敲入./configure --help 时,能看到选项的完整列表。一些选项对所有configure 脚本是通用的,还有一些是squid 专有的。下面是你可能用得到的标准选项:
    --perfix =PREFIX

    如前面描述的一样,这里设置安装目录。安装目录是所有可执行文件,日志,和配置文件的默认目录。在整本书中,$prefix 指你选择的安装目录。

    --localstatedir =DIR
    该选项允许你改变var 目录的安装位置。默认是$prefix/var,但也许你想改变它,以使squid 的磁盘缓存和日志文件被存储在别的地方。

    --sysconfdir =DIR
    该选项允许你改变etc 目录的位置。默认的是$prefix/etc。假如你想使用/usr 作为安装位置,你也许该配置--sysconfdir为/etc.

    以下是squid 的专有./configure选项:

    --enable-dlmalloc[=LIB]
    在一些系统上,内建的内存分配机制(malloc)在使用squid 时表现不尽人意。使用--enable-dlmalloc 选项将squid 源代码包中的dlmalloc 包编译和链接进来。假如你的系统中已安装dlmalloc,你能使用=LIB 参数指定库的路径。请见http://g.oswego.edu/dl/html/malloc.html更多关于dlmalloc 的信息。

    --enable-gnuregex
    在访问控制列表和其他配置指令里,squid 使用正则表达式作为匹配机制。GNU 的正则表达式库包含在squid 的源代码包里;它可以在没有内建正则表达式的操作系统中使用。./configure脚本侦察你系统中的正则表达式库,假如必要,它可以激活使用GNU正则表达式。如果因为某些理由,你想强制使用GNU正则表达式,你可以将这个选项加到./configure命令后。

    --enable-carp
    Cache数组路由协议(CARP)用来转发丢失的cache到父cache的数组或cluster。在10.9章有更多关于CARP的细节。

    --enable-async-io[=N_THREADS]
    同步I/O 是squid 技术之一,用以提升存储性能。aufs 模块使用大量的线程来执行磁盘I/O 操作。该代码仅仅工作在linux 和solaris 系统中。=N_THREADS 参数改变squid 使用的线程数量。aufs 和同步I/O 在8.4 章中被讨论。
    请注意--enable-async-io 是打开其他三个./configure 选项的快捷方式,它等同于:
    --with-aufs-threads=N_THREADS
    --with-pthreads
    --enable-storeio=ufs,aufs
    --with-pthreads

    该选项导致编译过程链接到你系统中的P 线程库。aufs 存储模块是squid 中唯一需要使用线程的部分。通常来说,如果你使用--enable-saync-io 选项,那么不必再单独指定该选项,因为它被自动激活了。

    --enable-storeio=LIST
    Squid 支持大量的不同存储模块。通过使用该选项,你告诉squid 编译时使用哪个模块。在squid-2.5 中,支持ufs,aufs,diskd,和null 模块。通过查询src/fs 中的目录,你能得到一个模
    块列表。
    LIST 是一个以逗号分隔的模块列表,例如:
    % ./configure --enable-storeio=afus,diskd,ufs

    ufs 模块是默认的,看起来问题最少。不幸的是,它性能有限。其他模块可能在某些操作系统中不必编译。关于squid 存储模块的完整描述,请见第8章。
    --with-aufs-threads=N_THREADS

    指定aufs 存储机制使用的线程数量(见8.4章)。squid 默认根据缓存目录的数量,自动计算需要使用多少线程。

    --enable-heap-replacement
    该选项不再使用,但被保留用于向后兼容性。你该使用--enable-removal-policies 来代替。

    --enable-removal-policies=LIST
    排除策略是squid 需要腾出空间给新的cache目标时,用以排除旧目标的机制。squid-2.5支持3个排除策略:最少近期使用(LRU),贪婪对偶大小(GDS),最少经常使用(LFU)。

    然而,因为一些理由,./configure 选项使指定的替代策略和需要执行它们的基本数据结构之间的差别模糊化。LRU是默认的,它以双链表数据结构执行。GDS和LFU使用堆栈的数据结构。

    为了使用GDS 或LFU 策略,你指定:
    % ./configure --enable-removal-policies=heap

    然后你在squid 的配置文件里选择使用GDS或LFU。假如你想重新使用LRU,那么指定:
    % ./configure --enable-removal-policies=heap,lru
    更多的关于替换策略的细节请见7.5 章。

    --enable-icmp
    如在10.5 章中描述的一样,squid 能利用ICMP消息来确定回环时间尺寸,非常象ping程序。你能使用该选项来激活这些功能。

    --enable-delay-pools
    延时池是squid 用于传输形状或带宽限制的技术。该池由大量的客户端IP 地址组成。当来自这些客户端的请求处于cache 丢失状态,他们的响应可能被人工延迟。关于延时池的更多细节请见附录C。

    --enable-useragent-log
    该选项激活来自客户请求的HTTP 用户代理头的日志。更多细节请见13.5 章。

    --enable-referer-log
    该选项激活来自客户请求的HTTP referer 日志。更多细节请见13.4 章。

    --disable-wccp
    Web cache 协调协议(WCCP)是CISCO 的专有协议,用于阻止或分发HTTP 请求到一个或多个caches。WCCP默认被激活,假如你愿意,可以使用该选项来禁止该功能。

    --enable-snmp
    简单网络管理协议(SNMP)是监视网络设备和服务器的流行方法。该选项导致编译过程去编译所有的SNMP相关的代码,包括一个裁切版本的CMU SNMP库。

    --enable-cachemgr -hostname[=hostname]
    cachemgr 是一个CGI程序,你能使用它来管理查询squid。默认cachemgr的hostname值是空的,但你能使用该选项来指定一个默认值。例如:
    % ./configure --enable-cachemgr-hostname=mycache.myorg.net

    --enable-arp-acl
    squid 在一些操作系统中支持ARP,或者以太地址访问控制列表。该代码使用非标准的函数接口,来执行ARP访问控制列表,所以它默认被禁止。假如你在linux或solaris上使用squid,你可能用的上这个功能。

    --enable-htcp
    HTCP 是超文本缓存协议--类似于ICP的内部缓存协议。更多细节请见10.8 章。

    --enable-ssl
    使用该选项赋予squid 终止SSL/TLS 连接的能力。注意这仅仅工作在web加速器中用以加速请求。更多细节请见15.2.2 章节。

    --with-openssl[=DIR]
    假如必要,你使用该选项来告诉squid到哪里找到OpenSSL库或头文件。假如它们不在默认位置,在该选项后指定它们的父路径。例如:
    % ./configure --enable-ssl --with-ssl=/opt/foo/openssl
    在这个例子中,你的编译器将在/opt/foo/openssl/include目录中找头文件, 在/opt/foo/openssl/lib 中找库文件。

    --enable-cache-digests
    Cache 消化是ICP 的另一个替代,但有着截然不同的特性。请见10.7 章。

    --enable-err-languages="lang1 lang2 ..."
    squid支持定制错误消息,错误消息可以用多种语言报告。该选项指定复制到安装目录($prefix/share/errors)的语言。假如你不使用该选项,所有可用语言被安装。想知道何种语言可用,请见源代码包里errors目录下的目录列表。如下显示如何激活多种语言:
    % ./configure --enable-err-languages="Dutch German French" ...

    --enable-default-err-language=lang
    该选项设置error_directory 指令的默认值。例如,假如你想使用荷兰语,你能这样指定:
    % ./configure --enable-default-err-language=Dutch
    你也能在squid.conf 里指定error_directory 指令,在附录A 中有描述。假如你忽略该选项,英语是默认错误语言。

    --with-coss-membuf-size=N
    循环目录存储系统(coss)是squid 的试验性存储机制。该选项设置coss 缓存目录的内存缓冲大小。注意为了使用coss,你必须在--enable-storeio 选项里指定存储类型。
    该参数以字节形式赋值,默认是1048576 字节或1M。你能指定2M 缓冲如下:
    % ./configure --with-coss-membuf-size=2097152

    --enable-poll
    unix 提供两个相似的函数用以在I/O 事件里扫描开放文件描述符:select() 和poll()。./configure 脚本通常能非常好的计算出何时使用poll()来代替select().假如你想强制使用poll(),那么指定该选项。
    --desable-poll
    类似的,如果不使用poll(),那么指定该选项。

    --disable-http-violations
    squid 默认可以被配置成违背HTTP协议规范。你能使用该选项来删除违背HTTP协议的代码。

    --enable-ipf-transparent
    在第9章中,我将描述如何配置squid来拦截缓存。一些操作系统使用IP Filter包来协助拦截缓存。在这些环境下你应该使用该./configure 选项。如果你使用了该选项,但是编译器提示src/client_side.c文件出错,那是因为IP Filter包没有或没有正确的安装在你的系统中。

    --enable-pf-transparent
    你可能需要指定该选项,使用PF包过滤器在操作系统中拦截HTTP。PF是OpenBSD的标准包过滤器,也可能被发布到其他系统中。假如你使用该选项,但是编译器提示src/client_side.c 文件出错,那是因为PF 没有实际安装到你的系统中。

    --enable-linux-netfilter
    Netfilter 是linux 2.4 系列内核的包过滤器名字。假如你想在linux2.4或以后的版本中使用HTTP拦截功能,那么激活该选项。

    --disable-ident-lookups
    ident是一个简单的协议,允许服务器利用客户端的特殊TCP连接来发现用户名。假如你使用该选项,编译器将把执行这些查询的代码排除出去。即使你在编译时保留了这些代码,除非你在squid.conf文件里指定,squid不会执行ident查询。

    --disable-internal-dns
    squid 源代码包含两个不同的DNS 解决方案,叫做“内部的”和“外部的”。内部查询是默认的,但某些人可能要使用外部技术。该选项禁止内部功能,转向使用旧的方式。
    内部查询使用squid自己的DNS协议执行工具。也就是说,squid产生未完成的DNS查询并且将它们发送到一个解析器。假如超时,它重新发送请求,你能指定任意数量的解析器。该工具的有利处之一是,squid获得准确无误的DNS响应的TTLs。
    外部查询利用C库的gethostbyname()和gethostbyaddr()函数。squid使用一个外部进程池来制造并行查询。使用外部DNS 解析的主要弊端是你需要更多的辅助进程,增加squid的负载。另一个麻烦是C 库函数不在响应里传输TTLs,这样squid使用postive_dns_ttl 指令提供的一个常量值。

    --enable-truncate
    truncate()系统调用是unlink()的替代品。unlink()完全删除cache 文件,truncate()将文件大小设为零。这样做释放了分配给该文件的磁盘空间,但留下适当的目录接口。该选项存在的理由是,某些人相信(或希望)truncate()比unlink()性能表现更好。然而,压力测试显示两者有很少的或根本没有区别。

    --disable-hostname-checks
    默认的,squid要求URL主机名在一定程度上遵守古老的RFC 1034 规范:
    标签必须遵循下列ARPANET 主机名规则。它们必须以字母开始,以字母或数字结尾,仅仅包含字母,数字和下划线。
    这里字母意味着ASCII字符,从A到Z。既然国际域名日益流行,你可能希望使用该选项来移除限制。

    --enable-underscores
    该选项控制squid针对主机名里下划线的行为。通用的标准是主机名里不包含下划线字符,尽管有些人不赞成这点。squid默认会对URL主机名里带下划线的请求产生一条错误消息。你能使用该选项,让squid信任它们,把它们当作合法的。然而,你的DNS解析器也许强迫使用非下划线请求,并且对带下划线的主机名解析失败。

    --enable-auth[=LIST]
    该选项控制在squid的二进制文件里支持哪种验证机制。你能选择下列机制的任意组合:
    basic,digest,ntlm。假如你忽略该选项,squid 仅仅支持basic 验证。假如你使用不带参数的--enable-auth选项,编译进程将增加对所有验证机制的支持。你可以使用以逗号分隔的验证机制列表:
    % ./configure --enable-auth=digest,ntlm
    我在第六章和第十二章里会谈得更多。

    --enable-auth-helpers=LIST
    这个旧选项现在已舍弃了, 但为了保持向后兼容性仍保留着。你可以使用--enable-basic-auth-helperes=LIST 来代替。

    --enable-basic-auth-helpers=LIST
    使用该选项,你能将helpers/basic_auth 目录的一个或多个HTTP Basic验证辅助程序编译进来。请见12.2章找到它们的名字和描述。

    --enable-ntlm-auth-helpers=LIST
    使用该选项,你能将helpers/ntlm_auth 目录的一个或多个HTTP NTLM验证辅助程序编译进来。请见12.4章找到它们的名字和描述。

    --enable-digest-auth-modules=LIST
    使用该选项,你能将helpers/digest_auth 目录的一个或多个HTTP Digest验证辅助程序编译进来。请见12.3章找到它们的名字和描述。

    --enable-external-acl-helpers=LIST
    使用该选项,你能编译一个或多个扩展ACL辅助程序,这些在12.5章中讨论。例如:
    % ./configure --enable-external-acl-helpers=ip_user,ldap_group

    --disable-unlinkd
    unlinkd 是另一个squid的外部辅助进程。它的基本工作是对cache文件执行unlink()或truncate()系统调用。通过在外部进程里执行文件删除工作,能给squid带来明显的性能提升。使用该选项来禁止外部unlink进程功能。

    --enable-stacktrace
    某些系统支持在程序崩溃时,自动产生数据追踪。当你激活该功能后,如果squid崩溃,数据追踪信息被写到cache.log文件。这些信息对开发和程序bug调试有用。

    --enable-x-accelerator-vary
    该高级功能可能在squid被配置成加速器时使用。它建议squid在响应请求时,从后台原始服务器中寻找X-Accelerator-Vary头。请见15.5章。

    3.4.2 运行configure

    现在我们准备运行./configure 脚本。进入源代码的顶级目录敲入./configure,后面跟上前面提到过的任意选项,例如:
    % cd squid-2.5.STABLE4
    % ./configure --enable-icmp --enable-htcp

    ./configure 的工作就是侦察你的操作系统,以发现什么东西可用,什么不可用。它首先做的事情之一就是确认你的C编译器可用。假如./configure检测到你的C编译器有问题,脚本会退出,返回如下错误:
    configure: error: installation or configuration problem: C compiler
    cannot create executables.

    很可能你从不会看到这个消息。假如看到了,那意味着你的系统中没有C 编译器存在,或者编译器没有正确安装。请见config.log文件找到解决问题的建议。假如你的系统中有多个C编译器,你可以在运行./configure 之前设置CC环境变量,来告诉./configure使用哪个:
    % setenv CC /usr/local/bin/gcc
    % ./configure ...

    在./configure 检查完该编译器后,它查找头文件,库文件和函数的长列表。通常你不必担心该部分。在某些实际情况中,./configure会终止以引起你的注意,某些事情可能有问题,例如没有足够的文件描述符。假如你指定不完整的或不合理的命令行选项,它也会终止。假如有错误发生,请检查config.log 输出。./configure 的最终任务是创造Makefiles和其他文件,这些文件基于squid从你系统中了解到的知识。到此为止,你准备做编译工作。

    3.5 编译

    一旦./configure 完成了它的工作,你简单的敲入make 开始编译源代码:
    %make

    正常来说,该过程很顺利,你可以见到大量的滚动行。
    你也许见到一些编译器警告。大多数情况下,可以安全的忽略这些。假如这些警告非常多,并且一些看起来非常严重,请将它们报告给开发者,在第16.5 章中有描述。
    假如编译过程没有错误,你可以转移到下一节,描述如何安装你刚才编译的程序。
    为了验证编译是否成功,你可以再次运行make。你将看到如下输出:
    % make
    Making all in lib...
    Making all in scripts...
    Making all in src...
    Making all in fs...
    Making all in repl...
    'squid' is up to date.
    'client' is up to date.
    'unlinkd' is up to date.
    'cachemgr.cgi' is up to date.
    Making all in icons...
    Making all in errors...
    Making all in auth_modules...

    因为许多理由,编译步骤也许会失败,包括:

    源代码bugs

    通常squid源代码是完整的调试过的。然而,你也许会遇到某些bugs或问题从而阻止你编译。这种问题在新的开发版本中更容易出现,请将它们报告给开发者。


    编译器安装问题

    不正确安装的C编译器不能够编译squid或其他软件包。通常编译器随着操作系统预安装,所以你不必担心它。然而,假如你在操作系统安装完后,试图升级编译器,那么可能会犯错误。绝对不要把已经安装好的编译器从一台机器拷贝到另一台,除非你绝对清楚你在做什么。我觉得在每台机上独立的安装编译器总是最好的。

    请确认你的编译器的头文件总是与库文件同步。头文件通常在/usr/include目录,而库文件在/usr/lib目录。Linux的流行RPM系统允许它去升级其中之一,但并非另一个。假如库文件基于不同的头文件,squid不能编译。

    假如你想在开源BSD 变种之一中升级编译器,请确认在/usr/src目录中运行make world,这好过从/usr/src/lib 或/usr/src/include 中运行。


    如下是一些通用的编译器问题和错误消息:

    Solaris: make[1]: *** [libmiscutil.a] Error 255
    这意味着./configure 不能发现ar程序。请确认/usr/ccs/bin位于你的PATH环境变量里。假如你没有安装Sun 的编译器, 那么需要GNU 的工具。(http://www.gnu.org/directory/binutils.html).

    Linux: storage size of 'rl' isn't known
    这是因为头文件和库文件不匹配所致,象前面描述的一样。请确认同时升级两者。

    Digital Unix: Don't know how to make EXTRA_libmiscutil_a_SOURCES. Stop.
    Digital Unix的make 程序不能兼容automake 包产生的Makefile文件。例如,lib/Makefile.in包含如下行:
    noinst_LIBRARIES = \
    @LIBDLMALLOC@ \
    libmiscutil.a \
    libntlmauth.a \
    @LIBREGEX@
    在替换后,当lib/Makefile 被创建时,它看起来如下:
    noinst_LIBRARIES = \
    \
    libmiscutil.a \
    libntlmauth.a \
    <TAB>;
    象上面显示的一样,最后一行包括一个不可见的TAB字符,它阻止了make。通过安装和使用GNU make,或者手工编辑lib/Makefile 如下,来解决这个问题:
    noinst_LIBRARIES = \
    \
    libmiscutil.a \
    libntlmauth.a


    假如你在编译squid时遇到问题,请先检查FAQ。你也许该在Squid的web站点上搜索(使用主页里的搜索栏)。最后,假如你仍有问题,请发邮件到squid-users@squid-cache.org列表。

    3.6 安装

    在编译完后,你需要把程序安装到指定的目录。可能需要超级用户权限来把它们放置到安装目录。所以,请先切换到root:
    %su
    password:
    #make install

    假如你通过使用--enable-icmp 选项,激活了squid 的ICMP衡量功能,那么必须安装pinger程序。pinger 程序必须以超级用户权限安装,因为仅仅允许root 来发送和接受ICMP 消息。

    下列命令以相应的许可来安装pinger 程序:
    #make install-pinger

    在安装完后,你将在squid 的安装目录里(默认是/usr/local/squid)见到下列目录和文件:

    sbin
    sbin 目录的程序正常只能被root 启动

    sbin/squid
    Squid 的主程序

    bin
    bin 目录包含对所有用户可用的程序

    bin/RunCache
    RunCache是一个shell脚本,你能用它来启动squid。假如squid死掉,该脚本自动重启它,除非它检测到经常的重启。RunCache是一个时间遗留的产物,那时Squid还不是后台服务进程。在最近的版本里,RunCache很少用到,因为Squid自动重启它自身,当你不使用-N选项时。

    bin/RunAccel
    RunAccel 与RunCache 几乎一致,唯一的不同是它增加了一个命令行参数,告诉squid在哪里侦听HTTP 请求。

    bin/squidclient
    squidclient 是个简单的HTTP 客户端程序,你能用它来测试squid。它也有一些特殊功能,用以对运行的squid 进程发起管理请求。

    libexec
    libexec 目录传统的包含了辅助程序。有一些命令你不能正常的启动。然而,这些程序通常被其他程序启动。

    libexec/unlinkd
    unlinkd是一个辅助程序,它从cache目录里删除文件。如你后面看到的一样,文件删除是个性能瓶颈。通过在外部进程里执行删除操作,Squid提升了一些执行性能。

    libexec/cachemgr.cgi
    cachemgr.cgi是Squid管理功能的CGI接口。为了使用它,你需要拷贝该程序到你的WEB服务器的cgi-bin目录。在14.2章中有更多描述。

    libexec/diskd(optional)
    假如你指定了--enable-storeio=diskd,你才能看到它。

    libexec/pinger(optional)
    假如你指定了--enable-icmp,你才能看到它。

    etc
    etc 目录包含squid 的配置文件。

    etc/squid.conf
    这是squid的主要配置文件。初始的该文件包含了大量的注释,用以解释每一个选项做什么。在你理解了这些配置指令后,建议你删除这些注释,让配置文件更小和更容易阅读。注意假如该文件存在,安装过程不会覆盖该文件。

    etc/squid.conf.default
    这是从源代码目录中拷贝过来的默认配置文件。在升级了squid安装后,你也许发现有一份当前默认配置文件的拷贝是有用的。可能会增加新的配置指令,一些存在的旧指令可能有所改变。

    etc/mime.conf
    mime.conf文件告诉squid 对从FTP和Gopher服务器获取的数据使用何种MIME类型。该文件是一个关联文件名扩展到MIME类型的表。正常而言,你不必编辑该文件。然而,你可能需要增加特殊文件类型的接口,它们在你的组织内使用。

    etc/mime.conf.default
    这是从源代码目录里拷贝过来的默认mime.conf文件。

    share
    share目录通常包括squid的只读数据文件。

    share/mib.txt
    这是squid的SNMP管理信息基础(MIB)文件。squid自身不使用该文件,然而,你的SNMP客户端软件(例如snmpget和多路由走向图(MRTG))需要该文件,用以理解来自squid的SNMP对象可用。

    share/icons
    share/icons目录包含大量的小图标文件,squid用在FTP和Gopher目录列举里。正常而言,你不必担心这些文件,但如果需要,你可以改变它们。

    share/errors
    share/errors目录包含了squid显示给用户看的错误消息模板。这些文件在你安装squid时,从源代码目录拷贝而来。如果需要你可以编辑它们。然而,在每次运行make install时,安装过程总会覆盖它们。所以假如你想定制错误消息,建议你把它们放在不同的目录。

    var
    var目录包含了不是很重要的和经常变化的文件。这些文件你不必正常的备份它们。

    var/logs
    var/logs目录是squid 不同日志文件的默认位置。当你第一次安装squid 时,它是空的。一旦squid开始运行,你能在这里看到名字为access.log,cache.log和store.log这样的文件。

    var/cache
    假如你不在squid.conf文件里指定,这是默认的缓存目录(cache_dir)。第七章有关于缓存目录的所有细节。

    3.7 打补丁

    在你运行squid一段时间后,你可能发现需要打源代码补丁,用以修正bug或者增加试验性的功能。在squid-cache.org站点上,对重要的bug修正会发布补丁。假如你不想等到下一个官方发布版本,你能下载补丁,并且打到你的源代码中。然后你需要重新编译squid。

    为了打补丁-或者有时候叫差别文件-你需要一个叫做"patch"的程序。你的操作系统必须有该程序。如果没有,你可以从GNU工具集里下载(http://www.gnu.org/directory/patch.html).

    注意假如你在使用匿名CVS(见2.4 节),你不必担心补丁文件。当你升级源代码树时,CVS系统自动升级了补丁。

    为了打补丁,你必须把补丁文件存放在系统中某处。然后进入到squid的源代码目录,运行如下命令:

    % cd squid-2.5.STABLE4
    % patch < /tmp/patch_file

    默认的,在patch程序运行时,它告诉你它正在做什么。通常输出滚动非常快,除非有问题。你能安全的忽略它输出的offset NNN lines警告。假如你不想见到所有这些输出,使用-s选项选择安静模式。

    当补丁更新了源代码后,它创造了原始文件的拷贝。例如,假如你对src/http.c 打一个补丁,备份文件名就是src/http.c.orig。这样,假如你在打了补丁后想撤销这个操作,简单的重命名所有的.orig 文件到它们以前的格式。为了成功的使用该技术,建议你在打补丁之前删除所有的.orig 文件。

    假如patch 程序遇到问题,它停止运行并且给出建议。通常问题如下:

    在错误的目录运行patch程序——解决的方法是,进入到正确的目录,或者使用patch的-p选项。

    补丁已打过——patch会告诉你是否已打过补丁文件。在这样的情况下,它会问你是否撤销这个文件的补丁。

    patch 程序不能理解你赋给它的文件——补丁文件通常有三个风格:正常的,context的和unified的。旧版本的patch 程序可能不理解后两者的差异输出。从GNU的FTP站点获取最近的版本能解决该问题。

    损坏的补丁文件——假如你在下载和存储补丁文件时不小心,它有可能被损坏。有时候人们以email消息发送补丁文件,在新的窗口里,它们被简单的剪切和粘贴。

    在这样的系统中,剪切和粘贴能将Tab字符改变为空格,或者不正确的捆绑长行。这些改变混乱了patch。-l选项也许有用,但最好是正确的拷贝和存储补丁文件。

    某些时候patch不能应用部分或所有的差别文件——在这样的情况下,你能见到类似于Hunk 3 of 4 failed的消息。失败的部分被存储在命名为.rej的文件里。例如,假如在处理src/http.c时失败,patch 程序将该差别文件片断存为src/http.c.rej。在这样的情况下,你也许能手工修正这些问题,但它通常不值得这么做。假如你有大量的"failed hunks"或者.rej文件,建议你去下载最近源代码版本的完整新拷贝。

    在你打完补丁后,你必须重新编译squid。make的先进功能之一就是它仅仅编译改变了的文件。但有时候make不能理解错综复杂的依赖关系,它没有完整的重编译所需文件。为了安全起见,通常建议你去重编译所有文件。最好的方法是在开始编译之前清除源代码树:

    %make clean
    %make

    3.8 重运行configure

    有时候你可能发现有必要重新运行./configure。例如,假如你调整了内核参数,你必须再次运行./configure以使它能发现新设置。当你阅读本书时,你也发现你必须使用./configure选项来激活所需的功能。

    以相同的选项重运行./configure,使用如下命令:
    %config.status --recheck

    另一个技术是`touch config.status`文件,它更新了该文件的时间戳。这导致make在编译源代码之前,重新运行./configure脚本:
    % touch config.status
    % make

    如果增加或删除./configure选项,你必须重新敲入完整的命令行。假如你记不住以前的选项,请查看config.status文件的顶部。例如:
    % head config.status
    #! /bin/sh
    # Generated automatically by configure.
    # Run this file to recreate the current configuration.
    Squid 中文权威指南 16
    # This directory was configured as follows,
    # on host foo.life-gone-hazy.com:
    #
    # ./configure --enable-storeio=ufs,diskd --enable-carp \
    # --enable-auth-modules=NCSA
    # Compiler output produced by configure, useful for debugging
    # configure, is in ./config.log if it exists.

    在运行./configure之后,你必须再次编译和安装squid。安全起见,建议先运行make clean:
    %make clean
    %make

    请回想一下,./configure会缓存它在你系统中发现的东西。在这样的形式下,你可能想清除这些缓存,从头开始编译过程。假如喜欢,你可以简单的删除config.cache 文件。然后,下一次./configure运行时,它不会使用以前的数值。你也能恢复squid源代码树到它的configure之前的状态,使用如下命令:
    %make distclean

    这将删除所有的目标文件和其他被./configure和make程序产生的文件。


  • L-Blog: http://www.loveyuki.com
    由Loveyuki自主开发的基于 ASP+Access 的小型单用户BLOG,目前似乎已经停止更新了,但是用户群相当大,而且是国内相当多的BLOG系统的鼻祖。

    oblog: http://www.oioj.net

    多用户Blog,目前占据ASP多用户BLOG的大部分市场,2.X商业版已经实行免费,很值得继续关注与期待的国内作品。


    SLblog:http://SLblog.com

    多用户Blog,刚发展起来的,更新很快,感觉像是oblog和missblog的结合体,同时首创了Blog系统无限级分类和用户栏目的无限级分类,多功能在现编辑器。但界面不是很美观,好在模板和程序分离,方便修改。


    Misslog: http://www.misslog.com/blog

    多用户blog,每个blog可以有多个用户参与创作与维护,团队功能很强大!


    LBS: http://www.voidland.com/blog

    LBS早期基于L-Blog架构,自从LBS2推出以后,大部分属于自己的创作,模板很多,用户群也逐渐庞大。


    Z-Blog: http://www.rainbowsoft.org/zblog/

    今年发展相当快的Blog系统,官方提供了想当丰富的支持,也创造了比较好的交流环境,这是他的一大亮点。


    PJBlog: http://www.pjhome.net/

    基于ASP的单用户BLOG系统,由于其插件异常丰富,可扩展的功能很多,比较适合喜欢功能饱满的朋友。


    Alpar's Blog: http://blog.fz0132.com

    基于L-Blog架构,但是作了相当大程度的修改,全面兼容LBS^2 的Style,目前版本模板采用DIV+CSS,很值得期待后续发展。


    nblog: http://blog.nowans.com/

    一个基于Access的个人Blog程序,全生成静态页面,刚开始起步。


    blogx: http://www.blanksoft.com/blogx/


    d2kblog: http://www.d2ksoft.com/

    国外一个BLOG系统,支持多国语言页面内容和页面样式分离。


    KeeBlogSystem: http://keesky.com/blog/

    XUL后台管理,很有特点的一个BLOG系统。
  •  Lucene是一个高性能的java全文检索工具包,它使用的是倒排文件索引结构。该结构及相应的生成算法如下:

    0)设有两篇文章1和2
    文章1的内容为:Tom lives in Guangzhou,I live in Guangzhou too.
    文章2的内容为:He once lived in Shanghai.

    1)由于lucene是基于关键词索引和查询的,首先我们要取得这两篇文章的关键词,通常我们需要如下处理措施
    a.我们现在有的是文章内容,即一个字符串,我们先要找出字符串中的所有单词,即分词。英文单词由于用空格分隔,比较好处理。中文单词间是连在一起的需要特殊的分词处理。
    b.文章中的”in”, “once” “too”等词没有什么实际意义,中文中的“的”“是”等字通常也无具体含义,这些不代表概念的词可以过滤掉
    c.用户通常希望查“He”时能把含“he”,“HE”的文章也找出来,所以所有单词需要统一大小写。
    d.用户通常希望查“live”时能把含“lives”,“lived”的文章也找出来,所以需要把“lives”,“lived”还原成“live”
    e.文章中的标点符号通常不表示某种概念,也可以过滤掉
    在lucene中以上措施由Analyzer类完成

    经过上面处理后
        文章1的所有关键词为:[tom] [live] [guangzhou] [i] [live] [guangzhou]
        文章2的所有关键词为:[he] [live] [shanghai]

    2) 有了关键词后,我们就可以建立倒排索引了。上面的对应关系是:“文章号”对“文章中所有关键词”。倒排索引把这个关系倒过来,变成:“关键词”对“拥有该关键词的所有文章号”。文章1,2经过倒排后变成
    关键词   文章号
    guangzhou  1
    he         2
    i           1
    live       1,2
    shanghai   2
    tom         1

    通常仅知道关键词在哪些文章中出现还不够,我们还需要知道关键词在文章中出现次数和出现的位置,通常有两种位置:a)字符位置,即记录该词是文章中第几个字符(优点是关键词亮显时定位快);b)关键词位置,即记录该词是文章中第几个关键词(优点是节约索引空间、词组(phase)查询快),lucene中记录的就是这种位置。

    加上“出现频率”和“出现位置”信息后,我们的索引结构变为:
    关键词   文章号[出现频率]   出现位置
    guangzhou 1[2]               3,6
    he       2[1]               1
    i         1[1]               4
    live      1[2],2[1]           2,5,2
    shanghai  2[1]               3
    tom      1[1]               1

    以live 这行为例我们说明一下该结构:live在文章1中出现了2次,文章2中出现了一次,它的出现位置为“2,5,2”这表示什么呢?我们需要结合文章号和出现频率来分析,文章1中出现了2次,那么“2,5”就表示live在文章1中出现的两个位置,文章2中出现了一次,剩下的“2”就表示live是文章2中第 2个关键字。
        
    以上就是lucene索引结构中最核心的部分。我们注意到关键字是按字符顺序排列的(lucene没有使用B树结构),因此lucene可以用二元搜索算法快速定位关键词。
        
    实现时 lucene将上面三列分别作为词典文件(Term Dictionary)、频率文件(frequencies)、位置文件 (positions)保存。其中词典文件不仅保存有每个关键词,还保留了指向频率文件和位置文件的指针,通过指针可以找到该关键字的频率信息和位置信息。

        Lucene中使用了field的概念,用于表达信息所在位置(如标题中,文章中,url中),在建索引中,该field信息也记录在词典文件中,每个关键词都有一个field信息(因为每个关键字一定属于一个或多个field)。

         为了减小索引文件的大小,Lucene对索引还使用了压缩技术。首先,对词典文件中的关键词进行了压缩,关键词压缩为<前缀长度,后缀>,例如:当前词为“阿拉伯语”,上一个词为“阿拉伯”,那么“阿拉伯语”压缩为<3,语>。其次大量用到的是对数字的压缩,数字只保存与上一个值的差值(这样可以减小数字的长度,进而减少保存该数字需要的字节数)。例如当前文章号是16389(不压缩要用3个字节保存),上一文章号是16382,压缩后保存7(只用一个字节)。
        
        下面我们可以通过对该索引的查询来解释一下为什么要建立索引。
    假设要查询单词 “live”,lucene先对词典二元查找、找到该词,通过指向频率文件的指针读出所有文章号,然后返回结果。词典通常非常小,因而,整个过程的时间是毫秒级的。
    而用普通的顺序匹配算法,不建索引,而是对所有文章的内容进行字符串匹配,这个过程将会相当缓慢,当文章数目很大时,时间往往是无法忍受的。
  • 1. Prototype是什么?

    或许你还没有用过它, prototype.js 是一个由Sam Stephenson写的JavaScript包。这个构思奇妙编写良好的一段兼容标准的一段代码将承担创造胖客户端, 高交互性WEB应用程序的重担。轻松加入Web 2.0特性。

    如果你最近体验了这个程序包,你很可能会发现文档并不是它的强项之一。像所有在我之前的开发者一样,我只能一头扎进prototype.js的源代码中并且试验其中的每一个部分。 我想当我学习他的时候记写笔记然后分享给其他人将会很不错。

    我也一起提供了这个包的对象,类,方法和扩展的 非官方参考

    2. 通用性方法

    这个程序包里面包含了许多预定义的对象和通用性方法。编写这些方法的明显的目的就是为了减少你大量的重复编码和惯用法。

    2.1. 使用 $()方法

    $() 方法是在DOM中使用过于频繁的 document.getElementById() 方法的一个便利的简写,就像这个DOM方法一样,这个方法返回参数传入的id的那个元素。

    比起DOM中的方法,这个更胜一筹。你可以传入多个id作为参数然后 $() 返回一个带有所有要求的元素的一个 Array 对象。下面的例子会向你描述这些。

    <HTML>
    <HEAD>
    <TITLE> Test Page </TITLE>
    <script src="prototype-1.3.1.js"></script>
    
    <script>
        function test1()
        {
            var d = $('myDiv');
            alert(d.innerHTML);
        }
    
        function test2()
        {
            var divs = $('myDiv','myOtherDiv');
            for(i=0; i<divs.length; i++)
            {
                alert(divs[i].innerHTML);
            }
        }
    </script>
    </HEAD>
    
    <BODY>
        <div id="myDiv">
            <p>This is a paragraph</p>
        </div>
        <div id="myOtherDiv">
            <p>This is another paragraph</p>
        </div>
    
        <input type="button" value=Test1 onclick="test1();"><br>
        <input type="button" value=Test2 onclick="test2();"><br>
    
    </BODY>
    </HTML>

    这个方法的另一个好处就是你可以传入id字符串或者元素对象自己,这使得在创建可以传入任何形式参数的方法的时候, 它变得非常有用。

    2.2. 使用$F()方法

    $F()方法是另一个非常受欢迎的简写。它可以返回任何输入表单控件的值,如文本框或下拉框。 这个方法可以传入元素的id或者元素自己。

    <script>
        function test3()
        {
            alert(  $F('userName')  );
        }
    </script>
    
    <input type="text" id="userName" value="Joe Doe"><br> 
    <input type="button" value=Test3 onclick="test3();"><br>

    2.3. 使用Try.these()方法

    Try.these() 方法使得实现当你想调用不同的方法直到其中的一个成功正常的这种需求变得非常容易, 他把一系列的方法作为参数并且按顺序的一个一个的执行这些方法直到其中的一个成功执行,返回成功执行的那个方法的返回值。

    在下面的例子中, xmlNode.text在一些浏览器中好用,但是xmlNode.textContent在另一些浏览器中正常工作。 使用Try.these()方法我们可以得到正常工作的那个方法的返回值。

    <script>
    function getXmlNodeValue(xmlNode){
        return Try.these(
            function() {return xmlNode.text;},
            function() {return xmlNode.textContent;)
            );
    }
    </script>

    3. Ajax 对象

    上面提到的共通方法非常好,但是面对它吧,它们不是最高级的那类东西。它们是吗?你很可能自己编写了这些甚至在你的脚本里面有类似功能的方法。但是这些方法只是冰山一角。

    我很肯定你对prototype.js感兴趣的原因很可能是由于它的AJAX能力。所以让我们解释当你需要完成AJAX逻辑的时候,这个包如何让它更容易。

    Ajax 对象是一个预定义对象,由这个包创建,为了封装和简化编写AJAX 功能涉及的狡猾的代码。 这个对象包含一系列的封装AJAX逻辑的类。我们来看看它们的一些。

    3.1. 使用 Ajax.Request

    如果你不使用任何的帮助程序包,你很可能编写了整个大量的代码来创建XMLHttpRequest对象并且异步的跟踪它的进程, 然后解析出响应 然后处理它。当你不需要支持多于一种类型的浏览器时你会感到非常的幸运。

    为了支持 AJAX 功能。这个包定义了 Ajax.Request 类。

    假如你有一个应用程序可以通过url http://yoursever/app/get_sales?empID=1234&year=1998与服务器通信。它返回下面这样的XML 响应。

    <?xml version="1.0" encoding="utf-8" ?>
    <ajax-response>
        <response type="object" id="productDetails">
            <monthly-sales>
                <employee-sales>
                    <employee-id>1234</employee-id>
                    <year-month>1998-01</year-month>
                    <sales>$8,115.36</sales>
                </employee-sales>
                <employee-sales>
                    <employee-id>1234</employee-id>
                    <year-month>1998-02</year-month>
                    <sales>$11,147.51</sales>
                </employee-sales>
            </monthly-sales>
        </response>
    </ajax-response>

    Ajax.Request对象和服务器通信并且得到这段XML是非常简单的。下面的例子演示了它是如何完成的。

    <script>
        function searchSales()
        {
            var empID = $F('lstEmployees');
            var y = $F('lstYears');
            var url = 'http://yoursever/app/get_sales';
            var pars = 'empID=' + empID + '&year=' + y;
           var myAjax = new Ajax.Request(
                        url,
                        {method: 'get', parameters: pars, onComplete: showResponse}
                        );
    
        }
    
        function showResponse(originalRequest)
        {
            //put returned XML in the textarea
            $('result').value = originalRequest.responseText;
        }
    </script>
    
    <select id="lstEmployees" size="10" onchange="searchSales()">
        <option value="5">Buchanan, Steven</option>
        <option value="8">Callahan, Laura</option>
        <option value="1">Davolio, Nancy</option>
    </select>
    <select id="lstYears" size="3" onchange="searchSales()">
        <option selected="selected" value="1996">1996</option>
        <option value="1997">1997</option>
        <option value="1998">1998</option>
    </select>
    <br><textarea id=result cols=60 rows=10 ></textarea>

    你看到传入 Ajax.Request构造方法的第二个对象了吗? 参数{method: 'get', parameters: pars, onComplete: showResponse} 表示一个匿名对象的真实写法。他表示你传入的这个对象有一个名为 method 值为 'get'的属性,另一个属性名为 parameters 包含HTTP请求的查询字符串,和一个onComplete 属性/方法包含函数showResponse

    还有一些其它的属性可以在这个对象里面定义和设置,如 asynchronous,可以为truefalse 来决定AJAX对服务器的调用是否是异步的(默认值是 true)。

    这个参数定义AJAX调用的选项。在我们的例子中,在第一个参数通过HTTP GET命令请求那个url,传入了变量 pars包含的查询字符串, Ajax.Request 对象在它完成接收响应的时候将调用showResponse 方法。

    也许你知道, XMLHttpRequest在HTTP请求期间将报告进度情况。这个进度被描述为四个不同阶段:Loading, Loaded, Interactive, 或 Complete。你可以使 Ajax.Request 对象在任何阶段调用自定义方法 ,Complete 是最常用的一个。想调用自定义的方法只需要简单的在请求的选项参数中的名为 onXXXXX 属性/方法中提供自定义的方法对象。 就像我们例子中的 onComplete 。你传入的方法将会被用一个参数调用,这个参数是 XMLHttpRequest 对象自己。你将会用这个对象去得到返回的数据并且或许检查包含有在这次调用中的HTTP结果代码的 status 属性。

    还有另外两个有用的选项用来处理结果。我们可以在onSuccess 选项处传入一个方法,当AJAX无误的执行完后调用, 相反的,也可以在onFailure选项处传入一个方法,当服务器端出现错误时调用。正如onXXXXX 选项传入的方法一样,这两个在被调用的时候也传入一个带有AJAX请求的XMLHttpRequest对象。

    我们的例子没有用任何有趣的方式处理这个 XML响应, 我们只是把这段XML放进了一个文本域里面。对这个响应的一个典型的应用很可能就是找到其中的想要的信息,然后更新页面中的某些元素, 或者甚至可能做某些XSLT转换而在页面中产生一些HTML。

    更完全的解释,请参照 Ajax.Request 参考Ajax选项参考

    3.2. 使用 Ajax.Updater

    如果你的服务器的另一端返回的信息已经是HTML了,那么使用这个程序包中 Ajax.Updater 类将使你的生活变得更加得容易。用它你只需提供哪一个元素需要被AJAX请求返回的HTML填充就可以了,例子比我写说明的更清楚。

    <script>
        function getHTML()
        {
            var url = 'http://yourserver/app/getSomeHTML';
            var pars = 'someParameter=ABC';
    
             var myAjax = new Ajax.Updater('placeholder', url, {method: 'get', parameters: pars});
    
        }
    </script>
    
    <input type=button value=GetHtml onclick="getHTML()">
    <div id="placeholder"></div>

    你可以看到,这段代码比前面的例子更加简洁,不包括 onComplete 方法,但是在构造方法中传入了一个元素id。 我们来稍稍修改一下代码来描述如何在客户端处理服务器段错误成为可能。

    我们将加入更多的选项, 指定处理错误的一个方法。这个是用 onFailure 选项来完成的。

    我们也指定了一个 placeholder 只有在成功请求之后才会被填充。为了完成这个目的我们修改了第一个参数从一个简单的元素id到一个带有两个属性的对象, success (一切OK的时候被用到) 和 failure (有地方出问题的时候被用到) 在下面的例子中没有用到failure属性,而仅仅在 onFailure 处使用了 reportError 方法。

    <script>
        function getHTML()
        {
            var url = 'http://yourserver/app/getSomeHTML';
            var pars = 'someParameter=ABC';
            var myAjax = new Ajax.Updater(
                        {success: 'placeholder'},
                        url,
                        {method: 'get', parameters: pars, onFailure: reportError});
    
        }
    
        function reportError(request)
        {
            alert('Sorry. There was an error.');
        }
    </script>
    
    <input type=button value=GetHtml onclick="getHTML()">
    <div id="placeholder"></div>
    

    如果你的服务器逻辑是返回JavaScript 代码而不是单纯的 HTML 标记, Ajax.Updater对象可以执行那段JavaScript代码。为了使这个对象对待响应为JavaScript,你只需在最后参数的对象构造方法中简单加入evalScripts: true属性。

    更完全的解释,请参照 Ajax.Updater 参考Ajax选项参考

    4. prototype.js参考

    4.1. JavaScript 类的扩展

    prototype.js 包中加入功能的一种途径就是扩展已有的JavaScript 类。

    4.2. 对 Object 类的扩展

    Table 1. Object 类的扩展

    方法类别参数描述
    extend(destination, source)staticdestination: 任何对象, source: 任何对象用从 sourcedestination复制所有属性和方法的方式 来提供一种继承机制。
    extend(object)instance任何对象用从传入的 object 中复制所有属性和方法的方式 来提供一种继承机制。

    4.3. 对 Number 类的扩展

    Table 2. Number 类的扩展

    方法类别参数描述
    toColorPart()instance(none)返回数字的十六进制描述, 当在HTML中转换为RGB颜色组件到HTML中使用的颜色。

    4.4. 对 Function 类的扩展

    Table 3. 对 Function 类的扩展

    方法类别参数描述
    bind(object)instanceobject: 拥有这个方法的对象返回预先绑定在拥有该函数(=方法)的对象上的函数实例, 返回的方法将和原来的方法具有相同的参数。
    bindAsEventListener(object)instanceobject: 拥有这个方法的对象返回预先绑定在拥有该函数(=方法)的对象上的函数实例, 返回的方法将把当前的事件对象作为它的参数。

    让我们看看这些扩展的具体例子。

    <input type=checkbox id=myChk value=1> Test?
    <script>
        //declaring the class
        var CheckboxWatcher = Class.create();
    
        //defining the rest of the class implmentation
        CheckboxWatcher.prototype = {
    
           initialize: function(chkBox, message) {
                this.chkBox = $(chkBox);
                this.message = message;
                //assigning our method to the event
                this.chkBox.onclick = this.showMessage.bindAsEventListener(this);
           },
    
           showMessage: function(evt) {
              alert(this.message + ' (' + evt.type + ')');
           }
        };
    
    
        var watcher = new CheckboxWatcher('myChk', 'Changed');
    </script>

    4.5. 对 String 类的扩展

    Table 4. String 类的扩展

    方法类别参数描述
    stripTags()instance(none)返回一个把所有的HTML或XML标记都移除的字符串。
    escapeHTML()instance(none)返回一个把所有的HTML标记回避掉的字符串。
    unescapeHTML()instance(none)escapeHTML()相反。

    4.6. 对 document DOM 对象的扩展

    Table 5. document DOM 对象的扩展

    方法类别参数描述
    getElementsByClassName(className)instanceclassName: 关联在元素上的CSS类名返回给定的具有相同的CSS类名的所有元素。

    4.7. 对 Event 对象的扩展

    Table 6. Event 对象的扩展

    属性类型描述
    KEY_BACKSPACENumber8: 常量,退格(Backspace)键的代码。
    KEY_TABNumber9: 常量,Tab键的代码。
    KEY_RETURNNumber13: 常量,回车键的代码。
    KEY_ESCNumber27: 常量, Esc键的代码。
    KEY_LEFTNumber37: 常量,左箭头键的代码。
    KEY_UPNumber38: 常量,上箭头键的代码。
    KEY_RIGHTNumber39: 常量,右箭头键的代码。
    KEY_DOWNNumber40: 常量,下箭头键的代码。
    KEY_DELETENumber46: 常量,删除(Delete)键的代码。
    observers:Array缓存的观察者的列表,这个对象内部具体实现的一部分。

    Table 7. Event 对象的扩展

    方法类别参数描述
    element(event)staticevent: 事件对象返回引发这个事件的元素。
    isLeftClick(event)staticevent: 事件对象如果鼠标左键单击返回true。
    pointerX(event)staticevent: 事件对象返回在页面上x坐标。
    pointerY(event)staticevent: 事件对象返回在页面上y坐标。
    stop(event)staticevent: 事件对象用这个方法来中止事件的默认行为来使事件的传播停止。
    findElement(event, tagName)staticevent: 事件对象, tagName: 指定标记的名字向 DOM 树的上位查找,找到第一个给定标记名称的元素, 从这个元素开始触发事件。
    observe(element, name, observer, useCapture)staticelement: 对象或者对象id, name: 事件名 (如 'click', 'load', etc), observer: 处理这个事件的方法, useCapture: 如果true, 在捕捉到事件的阶段处理事件 那么如果 false在bubbling 阶段处理。加入一个处理事件的方法。
    stopObserving(element, name, observer, useCapture)staticelement: 对象或者对象id, name: 事件名 (如 'click', 'load', etc), observer: 处理这个事件的方法, useCapture: 如果true, 在捕捉到事件的阶段处理事件 那么如果 false在bubbling 阶段处理。删除一个处理实践的方法。
    _observeAndCache( element, name, observer, useCapture)static 私有方法,不用管它。
    unloadCache()static(none)私有方法,不用管它。清除内存中的多有观察着缓存。

    让我们看看怎样用这个对象加入处理 window 对象的load事件的处理方法。

    <script>
        Event.observe(window, 'load', showMessage, false);
    
        function showMessage() {
          alert('Page loaded.');
        }
    </script>

    4.8. 在 prototype.js中定义的新对象和类

    另一个这个程序包帮助你的地方就是提供许多既支持面向对象设计理念又有共通功能的许多对象。

    4.9. PeriodicalExecuter 对象

    这个对象提供一定间隔时间上重复调用一个方法的逻辑。

    Table 8. PeriodicalExecuter 对象

    方法类别参数描述
    [ctor](callback, interval)constructorcallback: 没有参数的方法, interval: 秒数创建这个对象的实例将会重复调用给定的方法。

    Table 9. PeriodicalExecuter 对象

    属性类型描述
    callbackFunction()被调用的方法,该方法不会被传入参数。
    frequencyNumber以秒为单位的间隔。
    currentlyExecutingBoolean表示这个方法是否正在执行。

    4.10. Prototype 对象

    Prototype 没有太重要的作用,只是声明了该程序包的版本 。

    Table 10. The Prototype object

    属性类型描述
    VersionString包的版本。
    emptyFunctionFunction()空方法对象。

    4.11. Class 对象

    在这个程序包中 Class 对象在声明其他的类时候被用到 。用这个对象声明类使得新类支持 initialize() 方法,他起构造方法的作用。

    看下面的例子

    //declaring the class
    var MySampleClass = Class.create();
    //defining the rest of the class implmentation
    MySampleClass.prototype = {
    
       initialize: function(message) {
            this.message = message;
       },
    
       showMessage: function(ajaxResponse) {
          alert(this.message);
       }
    };
    
    //now, let's instantiate and use one object
    var myTalker = new MySampleClass('hi there.');
    myTalker.showMessage(); //displays alert

    Table 11. Class 对象

    方法类别参数描述
    create(*)instance(any)定义新类的构造方法。

    4.12. Ajax 对象

    这个对象被用作其他提供AJAX功能的类的根对象。

    Table 12. Ajax 对象

    方法类别参数描述
    getTransport()instance(none)返回新的XMLHttpRequest 对象。

    4.13. Ajax.Base

    这个类是其他在Ajax对象中定义的类的基类。

    Table 13. Ajax.Base 类

    方法类别参数描述
    setOptions(options)instanceoptions: AJAX 选项设定AJAX操作想要的选项。
    responseIsSuccess()instance(none)返回 true 如果AJAX操作成功,否则为 false
    responseIsFailure()instance(none)responseIsSuccess() 相反。

    4.14. Ajax.Request

    继承自 Ajax.Base

    封装 AJAX 操作

    Table 14. Ajax.Request

    属性类型类别描述
    EventsArraystatic在AJAX操作中所有可能报告的事件/状态的列表。这个列表包括: 'Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'
    transportXMLHttpRequestinstance携带AJAX操作的 XMLHttpRequest 对象。

    Table 15. Ajax.Request

    方法类别参数描述
    [ctor](url, options)constructorurl: 请求的url, options: AJAX 选项创建这个对象的一个实例,它将在给定的选项下请求url。 重要:如果选择的url受到浏览器的安全设置,他会一点作用也不起。 很多情况下,浏览器不会请求与当前页面不同主机(域名)的url。 你最好只使用本地url来避免限制用户配置他们的浏览器(谢谢Clay)
    request(url)instanceurl: AJAX 请求的url这个方法通常不会被外部调用。已经在构造方法中调用了。
    setRequestHeaders()instance(none)这个方法通常不会被外部调用。 被这个对象自己调用来配置在HTTP请求要发送的HTTP报头。
    onStateChange()instance(none)这个方法通常不会被外部调用。 当AJAX请求状态改变的时候被这个对象自己调用。
    respondToReadyState(readyState)instancereadyState: 状态数字 (1 到 4)这个方法通常不会被外部调用。 当AJAX请求状态改变的时候被这个对象自己调用。

    4.15. options 参数对象

    AJAX操作中一个重要的部分就是 options 参数。 本质上没有options类。任何对象都可以被传入,只要带有需要的属性。通常会只为了AJAX调用创建匿名类。

    Table 16. options 参数对象

    属性类型Default描述
    methodArray'post'HTTP 请求方式。
    parametersString''在HTTP请求中传入的url格式的值列表。
    asynchronousBooleantrue指定是否做异步 AJAX 请求。
    postBodyStringundefined在HTTP POST的情况下,传入请求体中的内容。
    requestHeadersArrayundefined和请求一起被传入的HTTP头部列表, 这个列表必须含有偶数个项目, 任何奇数项目是自定义的头部的名称, 接下来的偶数项目使这个头部项目的字符串值。 例子:['my-header1', 'this is the value', 'my-other-header', 'another value']
    onXXXXXXXXFunction(XMLHttpRequest)undefined在AJAX请求中,当相应的事件/状态形成的时候调用的自定义方法。 例如 var myOpts = {onComplete: showResponse, onLoaded: registerLoaded};. 这个方法将被传入一个参数, 这个参数是携带AJAX操作的 XMLHttpRequest对象。
    onSuccessFunction(XMLHttpRequest)undefined当AJAX请求成功完成的时候调用的自定义方法。 这个方法将被传入一个参数, 这个参数是携带AJAX操作的 XMLHttpRequest对象。
    onFailureFunction(XMLHttpRequest)undefined当AJAX请求完成但出现错误的时候调用的自定义方法。 这个方法将被传入一个参数, 这个参数是携带AJAX操作的 XMLHttpRequest对象。
    insertionFunction(Object, String)null为了把返回的文本注入到一个元素中而执行的方法。 这个方法将被传入两个参数,要被更新的对象并且只应用于 Ajax.Updater的响应文本 。
    evalScriptsBooleanundefined, false决定当响应到达的时候是否执行其中的脚本块,只在 Ajax.Updater 对象中应用。
    decayNumberundefined, 1决定当最后一次响应和前一次响应相同时在 Ajax.PeriodicalUpdater 对象中的减漫访问的次数, 例如,如果设为2,后来的刷新和之前的结果一样, 这个对象将等待2个设定的时间间隔进行下一次刷新, 如果又一次一样, 那么将等待4次,等等。 不设定这个只,或者设置为1,将避免访问频率变慢。

    4.16. Ajax.Updater

    继承自 Ajax.Request

    当请求的url返回一段HTML而你想把它直接放置到页面中一个特定的元素的时候被用到。 如果url的返回<script> 的块并且想在接收到时就执行它的时候也可以使用该对象。含有脚本的时候使用 evalScripts 选项。

    Table 17. Ajax.Updater

    属性类型类别描述
    ScriptFragmentStringstatic可以判断是否为脚本的正则表达式。
    containersObjectinstance这个对象包含两个属性:AJAX请求成功执行的时候用到 containers.success , 否则的话用到 containers.failure

    Table 18. Ajax.Updater

    方法类别参数描述
    [ctor](container, url, options)constructorcontainer:可以是元素的id, 也可以是元素自己, 或者可以是带有2个属性的对象 - object.success AJAX请求成功的时候用到的元素(或者id) 否则用到object.failure 中设定的元素(或id) ,url: 请求的url, options: AJAX 选项创建一个用给定的选项请求给定的url的一个实例。
    updateContent()instance(none)这个方法通常不会被外部调用。 当响应到达的时候,被这个对象自己调用。 它会用HTML更新适当的元素或者调用在 insertion 选项中传入的方法-这个方法将被传入两个参数, 被更新的元素和响应文本。

    4.17. Ajax.PeriodicalUpdater

    继承自 Ajax.Base

    这个类重复生成并使用 Ajax.Updater 对象来刷新页面中的一个元素。或者执行 Ajax.Updater 可以执行的其它任务。更多信息参照 Ajax.Updater 参考

    Table 19. Ajax.PeriodicalUpdater

    属性类型类别描述
    containerObjectinstance这个值将直接传入Ajax.Updater的构造方法。
    urlStringinstance这个值将直接传入Ajax.Updater的构造方法。
    frequencyNumberinstance两次刷新之间的间隔 (不是频率) ,以秒为单位。 默认2秒。 This 当调用 Ajax.Updater 对象的时候,这个数将和当前的 decay 相乘。
    decayNumberinstance重负执行任务的时候保持的衰败水平。
    updaterAjax.Updaterinstance最后一次使用的 Ajax.Updater 对象
    timerObjectinstance通知对象该下一次更新时用到的JavaScript 计时器。

    Table 20. Ajax.PeriodicalUpdater

    方法类别参数描述
    [ctor](container, url, options)constructorcontainer:可以是元素的id, 也可以是元素自己, 或者可以是带有2个属性的对象 - object.success AJAX请求成功的时候用到的元素(或者id) 否则用到object.failure 中设定的元素(或id) ,url: 请求的url, options: AJAX 选项创建一个用给定的选项请求给定的url的一个实例。
    start()instance(none)这个方法通常不会被外部调用。 对象为了开始周期性执行任务的时候调用的方法。
    stop()instance(none)这个方法通常不会被外部调用。 对象为了停止周期性执行任务的时候调用的方法。
    updateComplete()instance(none)这个方法通常不会被外部调用。 被当前的 Ajax.Updater 使用,当一次请求结束的时候,它被用作计划下一次请求。
    onTimerEvent()instance(none)这个方法通常不会被外部调用。当到下一次更新时被内部调用。

    4.18. Element 对象

    这个对象提供在操作DOM中元素时使用的功能性方法。

    Table 21. Element 对象

    方法类别参数描述
    toggle(elem1 [, elem2 [, elem3 [...]]])constructorelemN: 元素对象或id切换每一个传入元素的可视性。
    hide(elem1 [, elem2 [, elem3 [...]]])instanceelemN: 元素对象或id用设定它的 style.display'none'来隐藏每个传入的元素。
    show(elem1 [, elem2 [, Slem3 [...]]])instanceelemN: 元素对象或id用设定它的 style.display ''来显示每个传入的元素。
    remove(element)instanceelement: 元素对象或id从document对象中删除指定的元素。
    getHeight(element)instanceelement: 元素对象或id返回元素的 offsetHeight
    addClassName( element, className)instanceelement: 元素对象或id, className: CSS类名向元素的类名中加入给定的类名。
    hasClassName( element, className)instanceelement: 元素对象或id, className: CSS类名返回 true 如果元素的类名中含有给定的类名
    removeClassName( element, className)instanceelement: 元素对象或id, className: CSS类名从元素的类名中删除给定的类名。
    cleanWhitespace( element )instanceelement: 元素对象或id删除该元素的所有只含有空格的子节点。

    4.19. Abstract 对象

    这个对象是这个程序包中其他类的根。它没有任何属性和方法。在这个对象中定义的类可以被视为传统的抽象类。

    4.20. Abstract.Insertion

    这个类被用作其他提供动态内容插入功能的类的基类,它像一个抽象类一样被使用。

    Table 22. Abstract.Insertion

    方法类别参数描述
    [ctor](element, content)constructorelement: 元素对象或id, content: 被插入的HTML创建一个可以帮助插入动态内容的对象。

    Table 23. Abstract.Insertion

    属性类型类别描述
    adjacencyStringstatic, parameter这个参数指定相对于给定元素,内容将被放置的位置。 可能的值是: 'beforeBegin', 'afterBegin', 'beforeEnd', 和 'afterEnd'.
    elementObjectinstance与插入物做参照元素对象。
    contentStringinstance被插入的 HTML 。

    4.21. Insertion 对象

    这个对象是其他类似功能的根。它没有任何属性和方法。在这个对象中定义的类仍然可以被视为传统的抽象类。

    4.22. Insertion.Before

    继承自 Abstract.Insertion

    在给定元素开始标记的前面插入HTML。

    Table 24. Insertion.Before

    方法类别参数描述
    [ctor](element, content)constructorelement: 元素对象或id, content: 被插入的HTML继承自 Abstract.Insertion. 创建一个可以帮助插入动态内容的对象。

    下面的代码

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>
    
    <script> new Insertion.Before('person', 'Chief '); </script>

    将把 HTML 变为

    <br>Hello, Chief <span id="person" style="color:red;">Wiggum. How's it going?</span>

    4.23. Insertion.Top

    继承自 Abstract.Insertion

    在给定元素第一个子节点位置插入 HTML。内容将位于元素的开始标记的紧后面。

    Table 25. Insertion.Top

    方法类别参数描述
    [ctor](element, content)constructorelement: 元素对象或id, content: 被插入的HTML继承自 Abstract.Insertion. 创建一个可以帮助插入动态内容的对象。

    下面的代码

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>
    
    <script> new Insertion.Top('person', 'Mr. '); </script>

    将把 HTML 变为

    <br>Hello, <span id="person" style="color:red;">Mr. Wiggum. How's it going?</span>

    4.24. Insertion.Bottom

    继承自 Abstract.Insertion

    在给定元素最后一个子节点位置插入 HTML。内容将位于元素的结束标记的紧前面。

    Table 26. Insertion.Bottom

    方法类别参数描述
    [ctor](element, content)constructorelement: 元素对象或id, content: 被插入的HTML继承自 Abstract.Insertion. 创建一个可以帮助插入动态内容的对象。

    下面的代码

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>
    
    <script> new Insertion.Bottom('person', " What's up?"); </script>

    将把 HTML 变为

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going? What's up?</span>

    4.25. Insertion.After

    继承自 Abstract.Insertion

    在给定元素结束标记的后面插入HTML。

    Table 27. Insertion.After

    方法类别参数描述
    [ctor](element, content)constructorelement: 元素对象或id, content: 被插入的HTML继承自 Abstract.Insertion. 创建一个可以帮助插入动态内容的对象。

    下面的代码

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>
    
    <script> new Insertion.After('person', ' Are you there?'); </script>

    将把 HTML 变为

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span> Are you there?

    4.26. Field 对象

    这个对象提供操作表单中的输入项目的功能性方法。

    Table 28. Field 对象

    方法类别参数描述
    clear(field1 [, field2 [, field3 [...]]])instancefieldN: 元素对象或id清除传入表单中项目元素的值。
    present(field1 [, field2 [, field3 [...]]])instancefieldN: 元素对象或id只有在所有的表单项目都不为空时返回 true
    focus(field)instancefieldN: 元素对象或id移动焦点到给定的表单项目。
    select(field)instancefieldN: 元素对象或id选择支持项目值选择的表单
  • 很多留言类似111111111111。。。。。。。

    加上style=" table-layout:fixed;word-break:break-all" 可以解决折行问题

  • IBM快捷热键表 


      Fn+F3:关闭屏幕,StandBy模式(待机),显示器、硬盘、音频被关闭,移动鼠标或按任意键解除。 
      Fn+F4:进入待机,Suspend模式(挂起),所有的任务都被停止并且保存到内存中,除了内存之外所有的设备都被停止,按下Fn键一秒钟以上解除。 
      Fn+F7:切换显示输出(LCD,或外接,或同时显示),这是一个循环转换的过程。 
      Fn+12:Hibernate模式(休眠),所有的任务被停止,并且内存和当前状态被保存到硬盘中,系统关机。 
      Fn+Home/End:增大/减少屏幕亮度,共有七档。 
      Fn+PgUp:开关屏幕灯。 
      某些机型按Fn+F3不能关闭屏幕

     
      在一些机型上如T22,运行WIN2000时按Fn+F3不能关闭屏幕,主要原因是Modem的驱动程序版本太低,把它升级到5.95以上通常会解决问题


  • --------------------------------------------------------------------------------
    -
    REGEDIT4

    ;恢复IE的标题及主页
    [HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main]
    "Window Title"="Internet Explorer"
    "Start Page"="about:blank"
    "Local Page"="about:blank"
    "Search Page"="about:blank"
    "First Home Page"=-
    "ChannelsFirstURL"=-
    "ChannelsURL"=-
    "Search Bar"=-
    "Default_Search_URL"=-
    "Default_Page_URL"=-

    [HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main]
    "Window Title"="Internet Explorer"
    "Start Page"="about:blank"
    "Default_Page_URL"="about:blank"
    "Default_Search_URL"= "about:blank"
    "Local Page"="about:blank"
    "Search Page"="about:blank"


    ;清除IE的“分级审查”密码
    [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Ratings]
    "Key"=-


    ;恢复右键菜单功能(多种)
    [HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Restrictions]
    "NoBrowserContextMenu"=dword:00000000

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoChangeStartMenu"=dword:00000000

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoTrayContextMenu"=dword:00000000

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoViewContextMenu"=dword:00000000

    ;解除IE的“Internet选项”及其对话框中所有属性设置的禁用
    [HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Restrictions]
    "NoBrowserOptions"=dword:00000000

    [HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Internet Explorer\Restrictions]
    "NoBrowserOptions"=dword:00000000

    [-HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Control Panel]


    ;解除资源管理器“文件夹选项”的禁用
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoFolderOptions"=dword:00000000


    ;解除“开始”菜单中的各种屏蔽
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoRun"=dword:00000000
    "NoFind"=dword:00000000
    "NoClose"=dword:00000000
    "NoFavoritesMenu"=dword:00000000
    "NoSetFolders"=dword:00000000
    "NoRecentDocsMenu"=dword:00000000
    "NoLogOff"=hex:00,00,00,00

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\WinOldApp]
    "NoRealMode"=dword:00000000

    ;解除“显示属性”及“任务栏属性”的禁用
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
    "NoDispCPL"=dword:00000000
    "NoDisp BackgroundPage"=dword:00000000
    "NoDispAppearancePage"=dword:00000000
    "NoDispScrSavPage"=dword:00000000
    "NoDispSettingsPage"=dword:00000000

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoSetTaskbar"=dword:00000000


    ;解除注册表编辑器的禁用
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
    "DisableRegistryTools"=dword:00000000


    ;解除“我的电脑”中驱动器的隐藏
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoDrives"=hex:00,00,00,00


    ;解除桌面的隐藏
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoDesktop"=dword:00000000


    ;解除MS-DOS窗口的限制
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\WinOldApp]
    "Disabled"=dword:00000000

    ;解除系统属性中“设备管理器”及“性能”的屏蔽
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
    "NoDevMgrPage"=dword:00000000
    "NoFileSysPage"=dword:00000000
    "NoVirtMemPage"=dword:00000000


    ;解除“网络属性”的禁用及其设置项的屏蔽
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoNetSetup"=dword:00000000

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Network]
    "NoEntireNetwork"=dword:00000000
    "NoNetSetupIDPage"=dword:00000000
    "NoNetSetupSecurityPage"=dword:00000000
    "NoWorkgroupContents"=dword:00000000
    "NoFileSharingControl"=dword:00000000




    ;取消系统启动时的对话框
    [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Winlogon]
    "LegalNoticeCaption"=""
    "LegalNoticeText"=""

    ;恢复桌面上IE、“我的文档”等系统级图标
    [HKEY_LOCAL_MACHINE\Software\CLASSES\CLSID\{871C5380-42A0-1069-A2EA-08002B30309D
    }\ShellFolder]
    "Attributes"=dword:00000024

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Documents]
    "HideMyDocsFolder"=-

    [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\explorer\Desktop\NameSpace\{450d8fba-ad25-11d0-98a8-0800361b1103}]
    @="我的文档"

    [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\explorer\Desktop\NameSpace\{645FF040-5081-101B-9F08-00AA002F954E}]
    @="回收站"

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoNetHood"=dword:00000000


    ;清除“按Web页方式查看活动桌面”里的网址
    [-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Desktop\Components]

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
    "ShellState"=-


    ;恢复任务栏中的日期格式
    [HKEY_CURRENT_USER\Control Panel\International]
    "sTimeFormat"="H:mm:ss"
    "s1159"="上午"
    "s2359"="下午"
    "iTime"="0"
    "iTLZero"="1"
    "sTime"=":"


    ;清除IE右键里多余的菜单
    [-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt]


    ;去掉IE“工具”菜单里多余的选项
    [-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Extensions]

    [-HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions]



    ;允许导入REG文件
    [HKEY_LOCAL_MACHINE\Software\Classes\.reg]
    @="regfile"
    [HKEY_LOCAL_MACHINE\Software\Classes\regfile\shell\open\command]
    @="regedit.exe \"%1\""

    ;解除IE的“文件”等菜单里的各项屏蔽
    [-HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Restrictions]

    [-HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Internet Explorer\Restrictions]


    ;恢复Outlook Express的标题
    [HKEY_CURRENT_USER\Software\Microsoft\Outlook Express]
    "WindowTitle"=""

    --------------------------------------------------------------------------------
  • 作者:南非蜘蛛 zhedou@sohu.com
    个人主页:http://douzhe.nease.net
    转载请保留作者信息


    在这里讨论这个问题,仅是为了研究,我个人认为,在unix上,让apache支持asp没有任何实际意义
    如果以前是在win上开发的asp,我想你就让到在win上好好用吧,不用费劲的移植到unix上了

    我是在solaris上测试的安装,其它系统,freebsd,linux和sco我想也差不多,忘大家测时候能反馈给我你的结果,谢谢
    好了,让我们开始吧
    下载相关软件
    apache_1.3.27.tar 下载:http://www.apache.org/dist
    Apache-ASP-2.49.tar 下载:http://cpan.org/modules/by-module/Apache/
    mod_perl-1.27.tar 下载:http://perl.apache.org/download/index.html
    stable.tar(perl-5.8.0) 下载:http://www.cpan.org/src/

    把上面的软件下载到一个目录,如test
    1:解压
    #tar xvf apache_1.3.27.tar
    #tar xvf Apache-ASP-2.49.tar
    #tar xvf mod_perl-1.27.tar

    2:安装apache
    为了以DSO的方式安装mod_perl,所以要有so模块
    #cd apache_1.3.27
    #./configure --prefix=/usr/local/apache
    #make
    #make install
    上面这样编译会有一些modules加不进来,我只好手动指定modules了,大家用下面的命令安装apache
    #./configure --prefix=/usr/local/apache --enable-module=auth_anon --enable-module=auth_dbm --enable-module=autoindex -

    -enable-module=cgi --enable-module=expires --enable-module=expires --enable-module=proxy --enable-module=rewrite -

    -enable-module=so
    #make
    #make install
    检查安装的模块
    #cd /usr/local/apache/bin/httpd -l
    Compiled-in modules:
    http_core.c
    mod_env.c
    mod_log_config.c
    mod_mime.c
    mod_negotiation.c
    mod_status.c
    mod_include.c
    mod_autoindex.c
    mod_dir.c
    mod_cgi.c
    mod_asis.c
    mod_imap.c
    mod_actions.c
    mod_userdir.c
    mod_alias.c
    mod_rewrite.c
    mod_access.c
    mod_auth.c
    mod_auth_anon.c
    mod_auth_dbm.c
    mod_proxy.c
    mod_expires.c
    mod_so.c
    mod_setenvif.c
    suexec: disabled; invalid wrapper /usr/local/apache/bin/suexe

    3:安装mod_perl
    % make -v
    % gcc -v
    % perl -v
    安装perl
    我得perl版本不够,所以我升级了一下perl的版本,现在是v5.8.0
    下载http://www.cpan.org/src/stable.tar
    #tar xvf stable.tar
    #cd perl-5.8.0/
    #make
    #make install
    到sunfreeware下载pkg的安装也可以,可能还更简单

    #cd mod_perl-1.27
    看看DSO编译的语法
    #grep DSO Makefile.PL
    照猫画虎
    #perl Makefile.PL EVERYTHING=1 DO_HTTPD=1 USE_APACI=1 USE_DSO=1 USE_APXS=1 WITH_APXS=/usr/local/apache/bin/apxs
    #make
    #make install

    测试mod_perl模块
    启动apache
    #telnet localhost 80
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    输入get Head /http /1.0
    HTTP/1.1 400 Bad Request
    Date: Wed, 25 Dec 2002 03:32:32 GMT
    Server: Apache/1.3.27 (Unix) mod_perl/1.27

    ok,mod_perl加上了


    给perl安装asp模块,一张方法是CPAN安装,一种是常规安装
    CPAN安装
    #perl -MCPAN -e shell
    cpan> install CPAN
    ...
    Installing the Apache::ASP bundle will automatically install all the modules
    Apache::ASP is dependent on as well as Apache::ASP itself. If you have
    trouble installing the bundle, then try installing the necessary modules one
    at a time:
    cpan> install MLDBM
    cpan> install MLDBM::Sync
    cpan> install Digest::MD5
    cpan> install Apache::ASP

    For extra/optional functionality in Apache::ASP 2.31 or greater, like
    support for formFill, XSLT, or SSI, you can install this bundle via CPAN:
    cpan> install Bundle::Apache::ASP::Extra

    也可以用常规的方法安装asp模块
    Otherwise, just copy ASP.pm to
    $PERLLIB/site/Apache
    > perl Makefile.PL
    > make
    > make test
    > make install

    安装完毕,进行测试
    在htdocs里vi一个test.asp,内容如下

    <!-- sample here -->
    <html>
    <body>
    For loop incrementing font size: <p>
    <% for(1..5) { %>
    <!-- iterated html text -->
    <font size="<%=$_%>" > Size = <%=$_%> </font> <br>
    <% } %>
    </body>
    </html>
    <!-- end sample here -->

    http://202.106.185.101/test.asp
    大家可以到这里看看效果

    good luck!

    参考文档
    http://www.apache-asp.org/install.html
    http://cpan.org/modules/by-module/Apache/Apache-ASP-2.49.readme
    http://perl.apache.org/docs/1.0/guide/getwet.html#Installing_mod_perl
    http://www.freelamp.com/new/publish/1015481268/index_html
  • 2005-11-03

    MBTI 测试报告

    您的人格类型是: ISFP(内向,感觉,情感,知觉)

    您的工作中的优势:
      ◆ 热情,慷慨
      ◆ 对自己关心的组织和个人忠诚
      ◆ 注重重要的细节,尤其是那些有关他人的细节
      ◆ 考虑周到,具备关注目前所需的能力
      ◆ 主动愿意支持组织的目标
      ◆ 具有准确评估目前形势的能力和能看出什么是最需要保持稳定的能力
      ◆ 能仔细评估地冒风险和使用新方式时的灵活性和主动性

    您工作中可能存在的不足:
      ◆ 往往只接受事物的表面现象而忽略事物深层次的暗示
      ◆ 没有能力观察到目前不存在的机会和选择
      ◆ 面对反面意见或者批评,往往很消极
      ◆ 不愿意提早准备某个事情,往往在时间安排上有问题
      ◆ 决断困难
      ◆ 不喜欢过多的规则和结构
      ◆ 在与自己的感受相矛盾时很难做出符合逻辑的决定
      ◆ 不愿意为坚持自己的想法和立场而冒险打破和他人和谐的关系
      ◆ 不会很自觉地对别人做直接地批评
      ◆ 如果有大量地及其复杂的任务,容易被压得喘不过气来
      ◆ 反对长期计划,很难按时完成任务

    : ISFP(内向,感觉,情感,知觉)
  • 本文主要解决两个问题:一个是如何将James的用户信息存储到数据库中,二是在进行James二次开发时,如何处理密码问题。本文面向对James有一定使用经验的用户,对于James的初学者,请先阅读我的另一篇文章《Apache James使用入门》。 

    一、James简介
    Apache James(Java Apache Mail Enterprise Server)是Apache组织的子项目之一,完全采用纯Java技术开发,实现了SMTP、POP3与NNTP等多种邮件相关协议。

    James也是一个邮件应用平台,可以通过Mailet扩充其功能,如Mail2SMS、Mail2Fax等。James提供了比较完善的配置方案,尤其是关于邮件内容存储和用户信息存储部分,可以选择在文件、数据库或其他介质中保存。

    James性能稳定、可配置性强,还是开源项目,所有源代码不存在版权问题,因此,James在项目中的应用日益广泛,现在常用版本为2.1,但最新版本2.3已经推出,在本文中,我们将仍以James2.1作为介绍蓝本。

    二、一个假设的项目
    假设我要以James为邮件服务器,开发一套基于Web的邮件系统,就像263.net,163.net一样,要求实现在线注册、在线收发邮件等功能。

    默认情况下,James的用户信息存储在文本中,虽然加了密,但由于文本存档不足,不便于查询及相应处理,幸好James提供了多种用户信息存储方案,如数据库存储,LDAP存储等。

    这里我们将以数据库存储为例,讲解用户信息的管理,数据库采用MySQL。当然你也可以采用LDAP,比如免费的OpenLDAP,功能非常强大。

    三、用户信息的数据库存储
    James邮件用户的用户信息默认保存在apps\james\var\users目录下,通过修改配置文件apps\james\SAR-INF\config.xml,可以把用户信息保存到数据库中,配置方法如下:

    第一步:在MySQL中新建一个数据库mail,用户名root,密码为空;

    第二步:打开config.xml,找到<users-store>这一项,此面默认的内容为:


    <repository name="LocalUsers" class="org.apache.james.userrepository.UsersFileRepository">
             <destination URL="file://var/users/"/>
    </repository> 



    需要修改为:

    <repository name="LocalUsers" class="org.apache.james.userrepository.JamesUsersJdbcRepository" destinationURL="db://maildb/users">
             <sqlFile>file://conf/sqlResources.xml</sqlFile>
          </repository> 



    通过修改,我们就把用户信息的存储介质从file改成了db,<sqlFile>是指明了在db中的数据表结构及相关数据库信息。

    第三步:仍然是config.xml,找到<data-sources>项,默认内容为空,把此项内容修改为:


    <data-source name="maildb" class="org.apache.james.util.mordred.JdbcDataSource">
                               <driver>org.gjt.mm.mysql.Driver</driver>
                                <dburl>jdbc:mysql://127.0.0.1/mail</dburl>
                                <user>root</user>
                                <password></password>
                                <max>20</max>
    </data-source>



    <driver>是指MySQL的JDBC驱动,<dburl>指数据库的访问路径,IP后的mail即MySQL中新建数据库名,接下来是用户名、密码及最大连接数。

    至此,数据库配置完成,启动James,若正常无误,请通过telnet添加一个新用户,比如adduser holen 123456,然后检查MySQL中的mail数据库,下面将有一个表users,这是James根据file://conf/sqlResources.xml的内容创建的。

    通过以上配置,James的用户信息就可以保存在数据库中了。

    四、密码问题
    当你通过telnet添加新用户时,比如adduser holen 123456,你可以查看数据库中的记录,第一个字段是holen,第二字段是密码,但密码并非123456,而一串“乱码”(zhwQUMTwdMqWfm/h0biB51Gf)??这是加密码后的密码内容,再看后面的字段是“SHA”,显然用的是SHA加密方式。

    通过telnet方式添加新用户,用户密码将自动加密,然后插入数据库中。但通过telnet方式进行用户管理有着诸多不便,尽管你可以借助James的一个RMI工具包,提高效率,但仍然没有本质改变,当需要用作商业用途时,你更不能要求你的客户熟记那一堆命令符。

    一般我们可以做一个Web前端,通过网页形式,添加修改用户,界面友好,傻瓜化使用,如263或163一样。若这样做,我们就需要直接操作数据库,添加用户记录或修改删除用户记录了。但别忘了,James默认对用户密码是加密的,既然我们要直接操作数据库,那么我们只有两个选择:要么我们研究其密码机制,添加记录时,我们对新增用户的密码进行同样加密,要么我们去掉James的加密机制,使其明码保存。

    幸好,这两种选择都是可行的。我们从Apache网站下载James的源码包,下载后的文件为james-2.1-src.zip,接近8M,通过分析源码,我们发现,与用户密码相关的文件是DefaultUser.java,部分源码如下:


    package org.apache.james.userrepository;
    ……
    /**
         *  Method to verify passwords. 
         *
         * @param pass the String that is claimed to be the password for this user
         * @return true if the hash of pass with the current algorithm matches
         * the stored hash.
         */
        public boolean verifyPassword(String pass) {
            try {
                String hashGuess = DigestUtil.digestString(pass, algorithm);
                return hashedPassword.equals(hashGuess);
            } catch (NoSuchAlgorithmException nsae) {
            throw new RuntimeException("Security error: " + nsae);
        }
        }
     
        /**
         * Sets new password from String. No checks made on guessability of
         * password.
         *
         * @param newPass the String that is the new password.
         * @return true if newPass successfuly hashed
         */
        public boolean setPassword(String newPass) {
            try {
                hashedPassword = DigestUtil.digestString(newPass, algorithm);
                return true;
            } catch (NoSuchAlgorithmException nsae) {
                throw new RuntimeException("Security error: " + nsae);
            }
    }
    ……



    第一个方法verifyPassword()是用来做密码认证,传入的参数是明文密码,通过DigestUtil.digestString()方法,转换成密文密码,然后与数据库中密码作比较,返回比较结果。请注意这里的DigestUtil.digestString()方法,在后面还在提到。

    第二个方法setPassword()是用于密码转换的,把明文转成密文,用的同样是DigestUtil.digestString()方法。

    谈到这里,相信你应该知道怎么在自己的程序中进行密码转换和密码认证了吧!其实并不是要你自己去写一个SHA的加密算法,既然James已经提供了此功能,你调用便是了。

    还有一种情况,开发者需要在数据库中必须用明文保存密码,这样就不必在自己写的程序中进行密码转换了,而且当多个应用系统采用统一用户模型时,最好只有一个用户实例。要实现这个需求,就只能修改James源代码了,把verifyPassword()方法和setPassword()改成:


    public boolean verifyPassword(String pass) {       
                return hashedPassword.equals(pass);       
    }   
    public boolean setPassword(String newPass) {      
                hashedPassword = newPass;
                return true;       
    }



    其实就是把转换过程去掉,保存和认证就都采用明文进行了。

    你要是觉得SHA方式不妥,也可以挂接别的加密方式,同样是修改这两个方法。

    注意,当你修改了James的源码后,你需要用Ant重新build James项目,build后将在james-2.1-src\dist\james-2.1\apps下面找到新生成的james.sar文件。把该文件覆盖James原来james.sar,并删除与james.sar同级的james目录,重启动james即可。建议保留原来的config.xml,免得又配一次。

    通过以上探讨,我们明白了如何通过Web方式进行用户注册和用户登记等。需要说明一点是,James自动生成的users表中只有7个字段,而且都是系统需要使用的。一般注册时需要输入的信息项比较多,这时建议开发者自己再建一个新表USERINFO,用username把两个表关联起来,不建议修改users表的内容(如果想试试,请参考file://conf/sqlResources.xml)。

    五、基于James的邮件系统开发方案简述
    James运行在Win2000上,客户端采用Web界面(仿263风格)、Foxmail或OutLook Express,该系统主要面向1000人以下的中小企业。

    基于James的邮件开发,主要包括两个方面:一是邮件系统的后台管理,另一个是客户端应用系统。

    后台管理的功能主要包括用户的添加、删除、修改、用户使用空间指配、邮件备份等。

    Web客户端功能包括收件箱、发邮件、发件箱、草稿箱、回收站、地址本、自定义文件夹、配置等。

    用户信息存储在MySQL数据库中,邮件内容默认存储在文档中。

    系统采用Struts架构,运行环境为Apache1.3+Tomcat4.1,数据库连接池采用Tomcat自带的DBCP。

    系统开发预计需60人天完成,开发人员需要掌握Struts和JavaMail。

    压力测试超过50个并发。

    六、参考资料

    James 2.1 Documentation 
  • Apache2 httpd.conf 中文版
    #
    # 基于 NCSA 服务的配置文件。
    #
    #这是Apache服务器主要配置文件。
    #它包含服务器的影响服务器运行的配置指令。
    #参见<URL:http://httpd.ache.org/doc-2.0/>以取得关于这些指令的详细信息
    #
    #不要只是简单的阅读这些指令信息而不去理解它。
    #这里只是做了简单的说明,如果你没有参考在线文件,你就会被警告。
    #
    #这些配置指令被分为下面三个部分:
    #1. 控制整个Apache服务器行为的部分(即全局环境变量)
    #2. 定义主要或者默认服务参数的指令,也为所有虚拟主机提供默认的设置参数
    #3. 虚拟主机的设置参数
    #
    #配置和日志文件名:如果你指定的文件名以“/”开始(win32下以“dirver:/”),
    #服务器将使用绝对路径,如果文件名不是以“/”开始的,那么它将把ServerRoot
    #的值附加在文件名的前面,例如,对“logs/foo.log",如果ServerRoot的值
    #为“/usr/local/apache2”,则该文件应为“/usr/local/apache2/logs/foo.log”
    #
    ##第一区:全局环境参数
    #
    #这里设置的参数将影响整个Apache服务器的行为;
    #例如Apache能够处理的并发请求的数量等。
    #
    #ServerRoot:指出服务器保存其配置、出错和日志文件等的根目录。
    #
    #注意!如果你想要将它指定为NFS或其它网络上的位置,
    #请一定要去阅读与LockFile有关的文档(可能在
    #<URL:http://httpd.apache.org/docs-2.0/mod/mpm_common.html#lockfile>)。
    #这将会使你自己也能解决很多问题。
    #
    #路径的结尾不要添加斜线。
    #
    ServerRoot "/usr/loacl/apache2"
    #
    #串行访问的锁文件必须保存在本地磁盘上
    #
    <IfModule !mpm_winnt.c>
    <IfModule !mpm_neware.c>
    #LockFile logs/accept.lock
    </IfModule>
    </IfModule>

    #ScoreBoardFile:用来保存内部服务进程信息的文件。
    #如果未指明(默认),记分板(scoreboard)将被保存在一个匿名的共享内存段中,
    #并且它不能被第三方软件所使用。
    #如果指定了,要确保不能使用两个Apache使用同一个记分板文件,
    #这个记分板文件必须保存在本地磁盘上。
    #
    <IfModule !mpm_netware.c>
    <IfModule !perchild.c>
    #ScoreBoardFile logs/apache_runtime_status
    <IfModule>
    <IfModule>

    #
    #PidFile:记录服务器启动进程号的文件。
    #
    <IfModule !mpm_neware.c>
    PidFile logs/httpd.pid
    </IfModule>

    #
    #Timeout:接收和发送前超时秒数
    #
    Timeout 300

    #
    #KeepAlive:是否允许稳固的连接(每个连接有多个请求),
    #设为"Off"则停用。
    #
    KeepAlive On

    #
    #MaxKeepAliveRequests:在稳固连接期间允许的最大请求数,
    #设为0表示无限制接入。
    #我们推荐你将其设为一个较大的值,以便提高性能
    MaxKeepAliveRequests 100

    #
    #KeepAliveTimeout:在同一个连接上从同一台客户上接收请求的秒数
    #
    KeepAliveTimeout 15

    ##
    ##Server-Pool大小设定(针对MPM的)
    ##

    # prefork MPM
    # StartServers:启动时服务器启动的进程数
    # MinSpareServers:保有的备用进程的最小数目
    # MaxSpareServers:保有的备用进程的最大数目
    # MaxClients:服务器允许启动的最大进程数
    # MaxRequestsPerChild:一个服务进程允许的最大请求数
    <IfModule prefork.c>
    StartServers 5
    MinSpareServers 5
    MaxSpareServers 10
    MaxClients 150
    MaxRequestPerChild 0
    </IfModule>

    # worker MPM
    # StartServers:服务器启动时的服务进程数目
    # MaxClients:允许同时连接的最大用户数目
    # MinSpareThreads:保有的最小工作线程数目
    # MaxSpareThreads:允许保有的最大工作线程数目
    # ThreadsPerChild:每个服务进程中的工作线程常数
    # MaxRequestsPerChild:服务进程中允许的最大请求数目
    <IfModule worker.c>
    StartServers 2
    MaxClients 150
    MinSpareThreads 25
    MaxSpareThreads 75
    ThreadsPerChild 25
    MaxRequestsPerChild 0
    </IfModule>

    # perchild MPM
    # NumServers:服务进程数量
    # StartThreads:每个服务进程中的起始线程数量
    # MinSpareThreads:保有的最小线程数量
    # MaxSpareThreads:保有的最大线程数量
    # MaxThreadsPerChild:每个服务进程允许的最大线程数
    # MaxRequestsPerChild:每个服务进程允许连接的最大数量
    <IfModule perchild.c>
    NumServers 5
    StartThreads 5
    MinSpareThreads 5
    MaxSpareThreads 10
    MaxThreadsPerChild 20
    MaxRequestsPerChild 0
    </IfModule>

    # WinNT MPM
    # ThreadsPerChild:服务进程中工作线程常数
    # MaxRequestsPerChild:服务进程允许的最大请求数
    <IfModule mpm_winnt.c>
    ThreadsPerChild 250
    MaxRequestsPerChild 0
    </IfModule>

    # BeOS MPM
    # StartThreads:服务器启动时启动的线程数
    # MaxClients:可以启动的最大线程数(一个线程等于一个用户)
    # MaxRequestsPerThread:每个线程允许的最大请求数
    <IfModule beos.c>
    StartThreads 10
    MaxClients 50
    MaxRequestsPerThread 10000
    </IfModule>

    # NetWare MPM
    # ThreadStachSize:为每个工作线程分配的堆栈尺寸
    # StartThreads:服务器启动时启动的线程数
    # MinSpareThreads:用于处理实发请求的空闲线程数
    # MaxSpareThreads:空闲线程的最大数量
    # MaxThreads:在同一时间活动的最大线程数
    # MaxRequestPerChild:一个线程服务请求的最大数量,
    # 推荐将其设置为0,以实现无限制的接入
    <IfModule mpm_netware.c>
    ThreadStackSize 65536
    StartThreads 250
    MinSpareThreads 25
    MaxSpareThreads 250
    MaxThreads 1000
    MaxRequestPerChild 0
    </IfModule>

    # OS/2 MPM
    # StartServers:启动的服务进程数量
    # MinSpareThreads:每个进程允许的最小空闲线程
    # MaxSpareThreads:每个进程允许的最大空闲线程
    # MaxRequestsPerChild:每个服务进程允许的最大连接数
    <IfModule mpmt_os2.c>
    StartServers 2
    MinSpareThreads 5
    MaxSpareThreads 10
    MaxRequestsPerChild 0
    </IfModule>

    #
    # Listen:允许你绑定Apache服务到指定的IP地址和端口上,以取代默认值
    # 参见<VirtualHost>指令
    # 使用如下命令使Apache只在指定的IP地址上监听,
    # 以防止它在IP地址0.0.0.0上监听
    #
    # Listen 12.34.56.78:80

    Listen 80

    #
    # 动态共享支持(DSO)
    #
    # 为了能够使用那些以DSO模式编译的模块中的函数,你必须有相应的“LoadModule”行,
    # 因此,在这里包含了这些指令,以便能在使用它之前激活。
    # 那些静态编译的模块不需要在这里列出 (即以“httpd -l”列出的模块)
    #
    # 示例:
    # LoadModule foo_module modules/mod_foo.so
    #

    #
    # ExtendedStatus:当调用“server-status”时,控制Apache是产生“全”状态
    # 信息(ExtendedStatus On),还是产生基本信息(ExtendedStatus Off)。
    # 默认为off
    #
    # ExtendedStatus On

    ### 第二区:“主”服务配置
    #
    # 这一区建立被 “主” 服务器用的指令值,以回应那些不被 <VirtualHost>
    # 定义处理的任何请求。
    # 这些数值也提供默认值给后面定义的<VirtualHost>容器。
    # 如果<VirtualHost>中有定义,那么这里定义的指令值将被
    # <VirtualHost>中的定义所覆盖。
    #

    <IfModule !mpm_winnt.c>
    <IfModule !mpm_neware.c>
    #
    # 如果你想使httpd以另外的用户或组来运行,你必须在开始时以root方式启动
    # 然后再将它切换为你想要使用的用户或组。
    #
    # User/Group:运行httpd的用户和组
    # 在SCO (ODT3)上使用“User nouser”和“Group nogroup”
    # 在HPUX上,你可能不能以nobody身份使用共享内存,建议创建一个www用户。
    # 注意一些核心(kernel)在组ID大于60000时拒绝setgid(Group)或semctl(IPC_SET),
    #节在这些系统上不要使用“Group #-1”。
    #
    User nobody
    Group #-1
    </IfModule>
    </IfModule>

    #
    # ServerAdmin:你的邮件地址,当发生问题时Apache将向你发出邮件。
    # 作为一个出错文档,这个地址显示在server-generated页上,
    # 例如:admin@your-domain.com
    #
    ServerAdmin admin@your-domain.com

    #
    # ServerName指定Apache用于识别自身的名字和端口号。
    # 通常这个值是自动指定的,但是我们推荐你显式的指定它以防止启动时出错
    #
    # 如果你为你的主机指定了一个无效的DNS名,server-generated重定向将不能工作。
    # 参见UseCanonicalName指令
    #
    # 如果你的主机没有注册DNS名,在这里键入它的IP地址
    # 无论如何,你必须使用它的IP地址来提供服务,
    # 这里使用一种容易理解的方式重定向服务
    ServerName localhost:80

    #
    # UseCanonicalName:决定Apache如何构造URLS和 SERVER_NAME 和 SERVER_PORT 的指令。
    # 当设置为 “Off”时,Apache会使用用户端提供的主机名和端口号。
    # 当设置为“On”,Apache会使用ServerName指令的值。
    #
    UseCanonicalName Off

    #
    # DocumentRoot:你的文档的根目录。默认情况下,所有的请求从这个目录进行应答。
    # 但是可以使用符号链接和别名来指向到其他的位置。
    #
    DocumentRoot "/home/redhat/public_html"

    #
    # Apache可以存取的每个目录都可以配置存取权限(包括它的子目录)。
    #
    # 首先,我们配置一个高限制的特征。

    # 这将禁止访问文件系统所在的目录,并添加你希望允许访问的目录块。
    # 如下所示
    <Directory />
    Order Deny,Allow
    Deny from all
    </Directory>

    #
    # 注意从这里开始你一定要明确地允许哪些特别的特征能够被使用。
    # - 所以,如果Apache没有象你所期待的那样工作的话,
    # 请检查你是否在下面明确的指定它可用。
    #

    #
    # 这将改变到你设置的DocumentRoot
    #
    <Directory "/home/redhat/public_html">

    #
    # Options:这个指令的值可以是“None”,“All”,或者下列选项的任意组合:
    # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    #
    # 注意,“MultiViews”必须被显式的指定,“Options All”不能为你提供这个特性。
    #
    # 这个指令既复杂又重要,请参见
    #“http://httpd.apache.org/docs-2.0/mod/core.html#optioins”以取得更多的信息。
    #
    Options FollowSymLinks

    #
    # AllowOverride控制那些被放置在.htaccess文件中的指令。
    # 它可以是“All”,“None”,或者下列指令的组合:
    # Options FileInfo AuthConfig Limit
    #
    AllowOverride None

    #
    # 控制谁可以获得服务。
    #
    Order allow,deny
    Allow from all

    </Directory>

    #
    # UserDir:指定在得到一个~user请求时将会添加到用户home目录后的目录名。
    #

    UserDir public_html

    # 为防止在UserDir指令上的漏洞,对root用户设置
    # 象“./”这样的UserDir是非常有用的。
    # 如果你使用Apache 1.3或以上版本,我们强烈建议你
    # 在你的服务器配置文件中包含下面的行

    UserDir disabled root

    #
    # 下面是一个使用UserDir指令使一个站点的目录具有只读属性的示例:
    #
    # <Directory /home/*/public_html>
    # AllowOverride FileInfo AuthConfig Limit Indexes
    # Options MultiViews Indexes SymLinksIfOwnerMatch IncludeNoExec
    # <Limit GET POST OPTIONS PROPFIND>
    # Order allow,deny
    # Allow from all
    # </Limit>
    # <LimitExcept GET POST OPTIONS PROPFIND>
    # Order deny,allow
    # Deny from all
    # </LimitExcept>
    # </Directory>

    #
    # DirectoryIndex:定义请求是一个目录时,Apache向用户提供服务的文件名
    #
    # index.html.var文件(一个类型映象文件)用于提供一个文档处理列表,
    # 出于同样的目的,也可以使用MultiViews选项,但是它会非常慢。
    #
    DirectoryIndex index.php index.html index.html.var

    #
    # AccessFileName:在每个目录中查询为目录提供附加配置指令的文件的文件名。
    # 参见AllowOverride指令。
    #
    AccessFileName .htaccess

    #
    # 下面的行防止.htaccess和.htpasswd文件被Web客户查看。
    #
    <Files ~ "^\.ht">
    Order allow,deny
    Deny from all
    </Files>

    #
    # Typeconfig:定义在哪里查询mime.types文件。
    #
    TypeConfig conf/mime.types

    #
    # DefaultType:定义当不能确定MIME类型时服务器提供的默认MIME类型。
    # 如果你的服务主要包含text或HTML文档,“text/plain”是一个好的选择;
    # 如果大多是二进制文档,诸如软件或图像,你应使用
    # “application/octer-stream”来防止浏览器象显示文本那样显示二进制文件。
    #
    DefaultType text/plain

    #
    # mod_mime_magic允许服务器从自己定义自己类型的文件中使用不同的线索(hints),
    # 这个MIMEMagicFile指令定义hints定义所在的文件。
    #
    <IfModule mod_mime_magic.c>
    MIMEMagicFile conf/magic
    </IfModule>

    #
    # HostnameLookups:指定记录用户端的名字还是IP地址,例如,本指令为on时
    # 记录主机名,如www.apache.org;为off时记录IP地址,204.62.129.132。
    # 默认值为off,这要比设为on好得多,因为如果设为on则每个用户端请求都将会
    # 至少造成对 nameserver 进行一次查询。
    #
    HostnameLookups Off

    #
    # EnableMMAP:控制是否进行内存转储(如果操作系统支持的话)。
    # 默认为on,如果你的服务器安装在网络文件系统上(NFS),请关闭它。
    # 在一些系统上,关闭它会提升系统性能(与文件系统类型无关);
    # 具体情况请参阅http://httpd.apache.org/docs-2.0/mod/core.html#enablemmap
    #
    # EnableMMAP off

    #
    # EnableSendfile:控制是否使用sendfile kernel支持发送文件
    # (如果操作系统支持的话)。默认为on,如果你的服务器安装在网络文件系统
    # (NFS)上,请你关闭它。
    # 参见http://httpd.apache.org/docs-2.0/mod/core.html#enablesendfile
    #
    # EnableSendfile off

    #
    # ErrorLog:错误日志文件定位。
    # 如果你没有在<VirtualHost>内定义ErrorLog指令,这个虚拟主机的错误信息
    # 将记录在这里。如果你在那儿定义了ErrorLog,这些错误信息将记录在你所
    # 定义的文件里,而不是这儿定义的文件。
    #
    ErrorLog logs/error_log

    #
    # LogLevel:控制记录在错误日志文件中的日志信息数量。
    # 可能的值包括:debug,info,notice,warn,error,crit,alert,emerg。
    #
    LogLevel warn

    #
    # 下面的指令为CustomLog指令定义格式别名。
    #
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common
    LogFormat "%{Referer}i -> %U" referer
    LogFormat "%{User-agent}i" agent

    # 你需要安装了mod_logio.c模块才能使用%I和%O。
    # LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio

    #
    # 指定接入日志文件的定位和格式(一般日志格式)。
    # 如果你没有在<VirtualHost>内定义这个指令,传输信息将记录在这里,
    # 如果你定义了这个指令,则记录在你指定的位置,而不是这儿定义的位置。
    #
    CustomLog logs/access_log common

    #
    # 如果你想要记录agent和referer信息,可以使用下面的指令
    #
    # CustomLog logs/referer_log referer
    # CustomLog logs/agent_log agent

    #
    # 如果你想要使用一个文件记录access,agent和referer信息,
    # 你可以如下定义这个指令:
    #
    # CustomLog logs/access_log combined

    #
    # ServerTokens
    # 这个指令定义包含在HTTP回应头中的信息类型。默认为“Full”,
    # 这表示在回应头中将包含模块中的操作系统类型和编译信息。
    # 可以设为列各值中的一个:
    # Full | OS | Minor | Minimal | Major | Prod
    # Full传达的信息最多,而Prod最少。
    #
    ServerTokens Full

    #
    # 随意的添加包含服务器版本和虚拟主机名字一行信息到server-generated输出页中
    # (内部错误文档,FTP目录列表,mod_status和mod_info输出等等,除了CGI错误
    # 或自定义的错误文档以外)。
    # 设为“EMail”将包含一个指向ServerAdmin的mailto:连接。
    # 可以为如下值:On | Off | EMail
    #
    ServerSignature On

    #
    # Aliases:在这时添加你需要的别名,格式如下:
    # Alias 别名 真实名
    #
    # 注意,如果你在别名的未尾包含了“/”,那么在URL中也需要包含“/”。
    # 因此,“/icons”不是这个示例中的别名。
    # 如果别名中以“/”结尾,那么真实名也必须以“/”结尾,
    # 如果别名中省略了结尾的“/”,那么真实名也必须省略。
    #
    # 我们使用别名“/icons/”来表示FancyIndexed目录列表,如果你不使用、
    # FancyIndexing,你可以注释掉它。
    #
    # Alias /icons/ "/usr/local/apache2/icons/"

    # <Directory "/usr/local/apache2/icons">
    # Options Indexes MultiViews
    # AllowOverride None
    # Order allow,deny
    ## Allow from all
    # </Directory>

    #
    # 这将改变ServerRoot/manual。这个别名提供了手册页所在的位置,
    # 即使你改变了你的DocumentRoot。如果你对有无手册页并不在意的话,
    # 你可以注释掉它。
    #
    Alias /manual "/usr/loacl/apache2/manual"

    <Directory "/usr/local/apache2/manual">
    Options Indexes FollowSymLinks MultiViews IncludesNoExec
    AddOutputFilter Includes html
    Order allow,deny
    Allow from all
    </Directory>

    #
    # ScriptAlias:指定包含服务脚本的目录。
    # ScriptAliases 本质上与Aliases一样,除了这里的文档在请求时做为程序处理处理以外。
    # 尾部的“/”规则与Alias一样
    #
    ScriptAlias /cgi-bin/ "/usr/loacl/apache2/cgi-bin/"

    # 这里是添加php 4支持的指令
    AddType application/x-httpd-php .php
    LoadModule php4_module modules/libphp4.so

    <IfModule mod_cgid.c>
    #
    # 添加mod_cgid.c设置,mod_cgid提供使用cgid进行通讯的UNIX套接字的
    # 脚本接口路径。
    #
    # Scriptsock logs/cgisock
    </IfModule>

    #
    # 将"/usr/local/apache2/cgi-bin"改为你的ScriptAliased指定的CGI目录,
    # 如果你配置了的话。
    #
    <Directory "/usr/local/apache2/cgi-bin">
    AllowOverride None
    Options None
    Order allow,deny
    Allow from all
    </Directory>

    #
    # Redirect允许你告诉客户端使用存在于服务器名字空间中的文档,
    # 而不是现在的,这帮助客户定位那些改变了位置的文档。
    # 例如:
    # Redirect permanent /foo http://www.example.com/bar

    #
    # 控制server-generated目录列表显示的指令
    #

    #
    # IndexOptions:控制server-generated目录列表显示特征。
    #
    IndexOptions FancyIndexing VersionSort

    #
    # AddIcon* 指令告诉服务器不同扩展名的图象文件如何显示,
    # 只适用于FancyIndexed指令
    #
    AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
    AddIconByType (TXT,/icons/text.gif) text/*
    AddIconByType (IMG,/icons/image2.gif) image/*
    AddIconByType (SND,/icons/sound2.gif) audio/*
    AddIconByType (VID,/icons/movie.gif) video/*

    AddIcon /icons/binary.gif .bin .exe
    AddIcon /icons/binhex.gif .hqx
    AddIcon /icons/tar.gif .tar
    AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
    AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
    AddIcon /icons/a.gif .ps .ai .eps
    AddIcon /icons/layout.gif .html .shtml .htm .pdf
    AddIcon /icons/text.gif .txt
    AddIcon /icons/c.gif .c
    AddIcon /icons/p.gif .pl .py
    AddIcon /icons/f.gif .for
    AddIcon /icons/dvi.gif .dvi
    AddIcon /icons/uuencoded.gif .uu
    AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
    AddIcon /icons/tex.gif .tex
    AddIcon /icons/bomb.gif core

    AddIcon /icons/back.gif ..
    AddIcon /icons/hand.right.gif README
    AddIcon /icons/folder.gif ^^DIRECTORY^^
    AddIcon /icons/blank.gif ^^BLANKICON^^

    #
    # DefaultIcon 为那些没有显式定义图标的文件提供处理
    #
    DefaultIcon /icons/unknown.gif

    #
    # AddDescription允许你在server-generated索引后放置一个简短的说明。
    # 只对FancyIndexed指令有效。
    # 格式:AddDescription "说明" 文件名
    #
    # AddDescription "GZIP compressed document" .gz
    # AddDescription "tar archive" .tar
    # AddDescription "GZIP compressed tar archive" .tgz

    #
    # ReadmeName指定服务器默认查找的README文件的名字,并添加到目录列表中
    #
    # HeaderName指定目录列表前缀文件的文件名
    ReadmeName README.html
    HeaderName HEADER.html

    #
    # IndexIgnore指定目录索引忽略并且不包含在列表中的文件名集合,
    # 支持shell类型的通配符。
    #
    IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t

    #
    # AddEncoding允许你在信息传送中使用(Mosaic/X 2.1+)解压缩信息,
    # 注意:不是所有的浏览器都支持这个选项。
    # 尽管名字相似,但是下列的指令与上面的FancyIndexing定制指令不同。
    #
    AddEncoding x-compress Z
    AddEncoding x-gzip gz tgz

    #
    # DefaultLanguage和AddLanguage允许你指定文档的语言。
    # 这使你可以让用户用容易理解的语言浏览文档。
    #
    # 指定默认的语言,这意味着所有没有指定语言的包都将使用该语言。
    # 多数情况下,你也许并不想设置它,除非你确信这样做是正确的。
    # 通常,不使用确定的语言比使用错误的语言要好。
    #
    # DefaultLanguage nl
    #
    # 注意1:作为语言关键字的词缀毫无疑问是不能一样的--采用波兰
    # 文的文档(网络标准语言代码是pl)将希望使用“AddLanguage pl .po”
    # 来避免与perl脚本的一般词缀产生二义性。
    #
    # 注意2: 下面的例子举例说明在一些范例中语言的二字符缩写与它的国家
    # 的二字符缩写不相同,例如 “Danmark/dk” 和 “Danmark/da” 的比较.
    #
    # 注意3: 在 “ltz” 的情况下我们使用三字符词缀,违犯了 RFC的规定,
    # 运行中将修复它并使用RFC1766标准取得参考数据。
    #
    # Danish (da) - Dutch (nl) - English (en) - Estonian (et)
    # French (fr) - German (de) - Greek-Modern (el)
    # Italian (it) - Norwegian (no) - Norwegian Nynorsk (nn) - Korean (ko)
    # Portugese (pt) - Luxembourgeois* (ltz)
    # Spanish (es) - Swedish (sv) - Catalan (ca) - Czech(cz)
    # Polish (pl) - Brazilian Portuguese (pt-br) - Japanese (ja)
    # Russian (ru) - Croatian (hr)
    #
    AddLanguage da .dk
    AddLanguage nl .nl
    AddLanguage en .en
    AddLanguage et .et
    AddLanguage fr .fr
    AddLanguage de .de
    AddLanguage he .he
    AddLanguage el .el
    AddLanguage it .it
    AddLanguage ja .ja
    AddLanguage pl .po
    AddLanguage ko .ko
    AddLanguage pt .pt
    AddLanguage nn .nn
    AddLanguage no .no
    AddLanguage pt-br .pt-br
    AddLanguage ltz .ltz
    AddLanguage ca .ca
    AddLanguage es .es
    AddLanguage sv .sv
    AddLanguage cz .cz
    AddLanguage ru .ru
    AddLanguage tw .tw
    AddLanguage zh-tw .tw
    AddLanguage hr .hr

    # LanguagePriority允许你在会话过程中优先使用一些语言。
    #
    # 以优先次序递减的方式列出它们。我们或多或少地采用按字母排列顺序的方式
    # 排列它们。也许你想要改变这个顺序。
    LanguagePriority en da nl et fr de el it ja ko no pl pt pt-br ltz ca es sv tw

    #
    # ForceLanguagePriority 允许你为MULTIPLE CHOICES(Prefer)[在通讯的情况下]
    # 或NOT ACCEPTABLE(Fallback)[没有可接受的语言匹配的情况]提供一个结果页。
    #
    ForceLanguagePriority Prefer Fallback

    #
    # 为发送出的所有页指定默认的字符集,这总是一个好主意,并且为你的
    # web站点的国际化打开了大门,这不正是你曾经想要的吗。同样地,指定
    # 默认字符集有一些小的损害,如一个使用iso-8859-1(latin1)标准命令
    # 的页面,除非以别的方式指定例如你仅仅以显式方式声明它。
    # 也有一些与那些总是鼓励你使用默认字符集的javascropt和URL语法有关
    # 的浏览器安全原因。
    #
    #AddDefaultCharset ISO-8859-1
    AddDefaultCharse GB2312

    #
    # 一般以文件扩展名的方式使用字符集。也许你想要避免与语言扩展发生
    # 碰撞,除非你在每次改变后都做了很好的测试。
    # 参见http://www.iana.org/assignments/character-sets以取得字符集
    # 的名字列表和它们各自的RFCs。
    #
    AddCharset ISO-8859-1 .iso8859-1 .latin1
    AddCharset ISO-8859-2 .iso8859-2 .latin2 .cen
    AddCharset ISO-8859-3 .iso8859-3 .latin3
    AddCharset ISO-8859-4 .iso8859-4 .latin4
    AddCharset ISO-8859-5 .iso8859-5 .latin5 .cyr .iso-ru
    AddCharset ISO-8859-6 .iso8859-6 .latin6 .arb
    AddCharset ISO-8859-7 .iso8859-7 .latin7 .grk
    AddCharset ISO-8859-8 .iso8859-8 .latin8 .heb
    AddCharset ISO-8859-9 .iso8859-9 .latin9 .trk
    AddCharset ISO-2022-JP .iso2022-jp .jis
    AddCharset ISO-2022-KR .iso2022-kr .kis
    AddCharset ISO-2022-CN .iso2022-cn .cis
    AddCharset Big5 .Big5 .big5
    # 对于俄语,使用了多个字符集(如何使用主要依靠客户端):
    AddCharset WINDOWS-1251 .cp-1251 .win-1251
    AddCharset CP866 .cp866
    AddCharset KOI8-r .koi8-r .koi8-ru
    AddCharset KOI8-ru .koi8-uk .ua
    AddCharset ISO-10646-UCS-2 .ucs2
    AddCharset ISO-10646-UCS-4 .ucs4
    AddCharset UTF-8 .utf8


    # 下面的字符集没有映射到一个特定的标准(iso)上,但是它们在浏览器
    # 中被广泛的支持。注意那些大写字母。
    # (它不应该,但是它是为兼容一些浏览器而做)
    #
    # 参见http://www.iana.org/assianments/character-sets以取得
    # 它们的列表。但是浏览器支持较少。
    #
    AddCharset GB2312 .gb2312 .gb
    AddCharset utf-7 .utf7
    AddCharset utf-8 .utf8
    AddCharset big5 .big5 .b5
    AddCharset EUC-TW .euc-tw
    AddCharset EUC-JP .euc-jp
    AddCharset EUC-KR .euc-kr
    AddCharset shift_jis .sjis

    #
    # AddType允许你为指定的文件类型添加或覆盖mime.types文件中配置的MIME
    #
    AddType application/x-tar .tgz
    AddType image/x-icon .ico

    #
    # AddHandler允许你映射确定的文件扩展名到“handlers”:
    # 与文件类型无关的行为。这既能编译到服务器中也可以添加到Action指令
    # 中(看下面)。
    # 为了在ScriptAliased指令指定的以外使用CGI脚本:
    #(要使它可用,你还需要在Options中添加“ExecCGI”。
    #
    # AddHandler cgi-script .cgi

    #
    # 对于那些包含他们自己的HTTP头的文件
    #
    # AddHandler send-as-is asis

    #
    # 对于server-parsed imagemap文件:
    #
    # AddHandler imap-file map

    #
    # agemap 文件:
    #
    #AddHandler imap- 文件映像

    #
    # 对于类型映像:(转移资源)
    #(这是默认的设定以允许Apache的“It Worked”页能多种语言分发)。
    #
    AddHandler type-map var

    #
    # 过滤器允许你在将它发送到客户端前进行处理。
    #
    # 为了在服务器端分析包含(SSI)的.shtml文档:
    # (要执行这个指令,你还需要在Options指令中添加“Includes”。)
    #
    # AddType text/html .shtml
    # AddOutputFilter INCLUDES .shtml

    #
    # Action让你定义当调用匹配的媒体文件时将要执行的脚本。这将减少
    # 那些经常使用的CGI脚本的URL路径名的重复输入。
    # 格式:Action media/type /cgi-script/location
    # 格式:Action handler-name /cgi-script/location
    #

    #
    # 可配置的错误应答有三种风格:
    # 1)plain text 2)local redirects 3) external redirects
    #
    # 一些示例:
    # ErrorDocument 500 "The server made a boo boo."
    # ErrorDocument 404 /missing.html
    # ErrorDocument 404 "/cgi-bin/missing_handler.pl"
    # ErrorDocument 402 http://www.example.com/subscription_info.html
    #

    #
    # 综合应用这些指令,我们可以创建一个国际化的出错应答。
    #
    # 我们使用Alias来重定向任意/error/HTTP_<error>.html.var应答到
    # 我们的多语言错误消息集合。使用正确的文本替代它。
    #
    # 通过加入下面的行,你就能够改变这些消息的显示,而不必改变
    # HTTP_<error>.html.var文件。
    #
    # Alias /error/include/ "/your/include/path/"
    #
    # 以将/usr/local/apache2/error/include/下的文件拷贝到/your/inclue/path/下
    # 开始,你可以创建你自己的文件集合,甚至是其于每个虚拟主机的。
    # 不管你的ServerSignature如何设置,默认的包含文件将显示你的
    # Aapche版本号和你的ServerAdmin邮件地址
    #
    # 国际化的错误文档需要mod_alias,mod_include和mod_negotiation三个
    # 模块。要激活它们,取消下面30行的注释符号

    # Alias /error/ "/usr/local/apache2/error/"
    #
    # <Directory "/usr/local/apache2/error">
    # AllowOverride None
    # Options IncludesNoExec
    # AddOutputFilter Includes html
    # AddHandler type-map var
    # Order allow,deny
    # Allow from all
    # LanguagePriority en de es fr it nl sv
    # ForceLanguagePriority Prefer Fallback
    # </Directory>
    #
    # ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var
    # ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var
    ErrorDocument 403 /error.php
    # ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var
    # ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var
    # ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var
    # ErrorDocument 410 /error/HTTP_GONE.html.var
    # ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var
    # ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var
    # ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var
    # ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var
    # ErrorDocument 415 /error/HTTP_SERVICE_UNAVAILABLE.html.var
    # ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var
    # ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var
    # ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var
    # ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var
    # ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var

    #
    # 下面的命令更改标准的HTTP应答行为以处理己知的浏览器问题。
    #
    BrowserMatch "Mozilla/2" nokeepalive
    BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
    BrowserMatch "RealPlayer 4\.0" force-response-1.0
    BrowserMatch "Java/1\.0" force-response-1.0
    BrowserMatch "JDK/1\.0" force-response-1.0

    #
    # 下面命令关闭对那些没有尾部“/”的目录的非GET请求的重定向,
    # 这些命令修复了微软的采用DAV方法不能正确处理重定向的WEB文件夹的问题。
    # Apple下的DAV文件系统和Gnome下的VFS对DAV的支持也是采用这样的方法
    # 进行处理的。
    #
    BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
    BrowserMatch "^WebDrive" redirect-carefully
    BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully
    BrowserMatch "^gnome-vfs" redirect-carefully

    #
    # 允许你使用URL:http://servername/server-status来通过mod_status生
    # 成并报告服务器状态信息。改变.example.com为你自己的域名。
    #
    # <Location /server-status>
    # SetHandler server-status
    # Order deny,allow
    # Deny from all
    # Allow from .example.com
    # </Location>

    #
    # 允许使用URL:http://servername/server-info来远程报告服务器配置信息
    # (需要mod_info.c支持)。改变“.example.com”为你自己的域名。
    #
    # <Location /server-info>
    # SetHandler server-info
    # Order deny,allow
    # Deny from all
    # Allow from .example.com
    # </Location>

    #
    # 代理服务器命令,去掉下面的行使代理服务可用。
    #
    # <IfModule mod_proxy.c>
    # ProxyRequests On
    # <Proxy *>
    # Order deny,allow
    # Deny from all
    # Allow from .example.com
    # </Proxy>

    #
    # 安装或关闭HTTP/1.1“通道”头处理。
    # (“Full”添加服务器版本信息,“Block”移掉所有输出“通道”头信息。
    # 可以设为下面各选项之一:Off | On | Full | Block
    #
    # ProxyVia On

    # 最好为代理服务安装高速缓冲,去掉下面几行的注释符号:
    # (没有CacheRoot则不缓冲)
    #
    # CacheRoot "/usr/local/apache2/proxy"
    # CacheSize 5
    # CacheGcInterval 4
    # CacheMaxExpire 24
    # CacheLastModifiedFactor 01
    # CacheDefaultExpire 1
    # NoCache a-domain.com another-domain.edu joes.garage-sale.com

    # </IfModule>
    # 代理命令结束。

    #
    # 附加的特定模块配置。
    #
    <IfModule mod_ssl.c>
    Include conf/ssl.conf
    </IfModule>

    ## 第三区:虚拟主机
    #
    # VirtualHost:你可以通过设置虚拟主机容器以实现在你的主机上保有多个
    # 域名/主机名。大多数配置信息只使用基于名字的虚拟主机,因此服务器
    # 不必担心IP地址的问题,下面的命令以*号代替虚拟主机名。
    #
    # 在你试着配置你的虚拟主机以前,请参见
    # URL:http://httpd.apache.org/docs-2.0/vhosts/>以取得更多的信息。
    #
    # 你可以使用命令行选项“-S”来检验你的虚拟主机配置。

    #
    # 使用基于名字的虚拟主机。
    #
    # NameVirtualHost *

    #
    # 虚拟主机示例:
    # 几乎所有的Apache命令都可以在虚拟主机容器中使用。
    # 第一个虚拟主机区是用于向服务名未知的请求进行应答的配置。
    #
    # <VirtualHost *>
    # ServerAdmin webmaster@dummy-host.example.com
    # DocumentRoot /www/docs/dummy-host.example.com
    # ServerName dummy-host.example.com
    # ErrorLog logs/dummy-host.example.com-error_log
    # CustomLog logs/dummy-host.example.com-access_log commom
    # </virtualHost>
  • 一、启动服务器
    1、解压压缩包
    2、设置JAVA_HOME
    3、运行\$jame_dir\$\bin\run.bat
    4、如果启动不了,清空\$jame_dir\$\apps\james 此目录下所有内容,重新运行run.bat会自动恢复默认设置

    二、配置服务器
    服务器配置文件路径: \$jame_dir\$\apps\james\SAR-INF\config.xml
    需要设置的地方:
    ----------DNS-----
    <dnsserver>
         <servers>
            
         <!--Enter ip address of your DNS server, one IP address per server -->
            
         <!-- element. -->
            
         <!--
              <server>127.0.0.1</server>
             -->
      
         <server>202.96.209.5</server>
            
         <server>202.96.0.133</server>
            
         <server>202.96.134.133</server>
         
         </servers>
          <!-- Change autodiscover to false if you would like to turn off autodiscovery -->
          <!-- and set the DNS servers manually in the <servers> section -->
          <autodiscover>true</autodiscover>
          <authoritative>false</authoritative>
       </dnsserver>

    -----------修改email管理器用户名,密码 -----
    <remotemanager>
          <port>4555</port>
          <!--  Uncomment this if you want to bind to a specific inetaddress -->
          <!--
          <bind> </bind>
          -->
          <!--  Uncomment this if you want to use TLS (SSL) on this port -->
          <!--
          <useTLS>true</useTLS>
          -->
          <handler>
             <!-- This is the name used by the server to identify itself in the RemoteManager -->
             <!-- protocol.  If autodetect is TRUE, the server will discover its -->
             <!-- own host name and use that in the protocol.  If discovery fails, -->
             <!-- the value of 'localhost' is used.  If autodetect is FALSE, James -->
             <!-- will use the specified value. -->
             <helloName autodetect="true">myMailServer</helloName>
             <administrator_accounts>
    <!-- CHECKME! -->
                <!-- Change the default login/password. -->
                <account login="root" password="root"/>
             </administrator_accounts>
             <connectiontimeout> 60000 </connectiontimeout>
          </handler>
       </remotemanager>

     ----------允许使用SMTP发送邮件的地址-------
     <authorizedAddresses>127.0.0.0/8,219.137.111.111</authorizedAddresses>

     


    三、管理服务器
    1、用telnet链接email管理服务器,
     命令: telnet servername port
     example:telnet www.xxx.com.cn 4555

    2、输入用户名,密码
    3、增加email用户: adduser username password
    4、列出当前服务器内用户: listusers

    example:
    JAMES Remote Administration Tool 2.1.2
    Please enter your login and password
    Login id:
    root
    Password:
    root
    Welcome root. HELP for a list of commands
    adduser red red
    User red added
    adduser green green
    User green added
    adduser blue blue
    User blue added
    listusers
    Existing accounts 3
    user: blue
    user: green
    user: red
    quit
    Bye

  • 2005-10-26

    AJAX基础教程

    这篇文章将带您浏览整个AJAX的基本概貌,并展示两个简单的例子让您轻松上路.

      什么是 AJAX?
      AJAX (异步 JavaScript 和 XML) 是个新产生的术语,专为描述JavaScript的两项强大性能.这两项性能在多年来一直被网络开发者所忽略,直到最近Gmail, Google suggest和google Maps的横空出世才使人们开始意识到其重要性.

      这两项被忽视的性能是:
      无需重新装载整个页面便能向服务器发送请求.
      对XML文档的解析和处理.

    步骤 1 – "请!" --- 如何发送一个HTTP请求

      为了用JavaScript向服务器发送一个HTTP请求, 需要一个具备这种功能的类实例. 这样的类首先由Internet Explorer以ActiveX对象引入, 被称为XMLHTTP. 后来Mozilla, Safari 和其他浏览器纷纷仿效, 提供了XMLHttpRequest类,它支持微软的ActiveX对象所提供的方法和属性.

      因此, 为了创建一个跨浏览器的这样的类实例(对象), 可以应用如下代码:

    if (window.XMLHttpRequest) { // Mozilla, Safari, ...
        http_request = new XMLHttpRequest();
    } else if (window.ActiveXObject) { // IE
        http_request = new ActiveXObject("Microsoft.XMLHTTP");
    }

      (上例对代码做了一定简化,这是为了解释如何创建XMLHTTP类实例. 实际的代码实例可参阅本篇步骤3.)

      如果服务器的响应没有XML mime-type header,某些Mozilla浏览器可能无法正常工作. 为了解决这个问题, 如果服务器响应的header不是text/xml,可以调用其它方法修改该header.

    http_request = new XMLHttpRequest();
    http_request.overrideMimeType('text/xml');

      接下来要决定当收到服务器的响应后,需要做什么.这需要告诉HTTP请求对象用哪一个JavaScript函数处理这个响应.可以将对象的onreadystatechange属性设置为要使用的JavaScript的函数名,如下所示:

    http_request.onreadystatechange = nameOfTheFunction;

      注意:在函数名后没有括号,也无需传递参数.另外还有一种方法,可以在扉页(fly)中定义函数及其对响应要采取的行为,如下所示:

    http_request.onreadystatechange = function(){
        // do the thing
    };

      在定义了如何处理响应后,就要发送请求了.可以调用HTTP请求类的open()和send()方法, 如下所示:

    http_request.open('GET', 'http://www.example.org/some.file', true);
    http_request.send(null);

      open()的第一个参数是HTTP请求方式 – GET, POST, HEAD 或任何服务器所支持的您想调用的方式. 按照HTTP规范,该参数要大写;否则,某些浏览器(如Firefox)可能无法处理请求.有关HTTP请求方法的详细信息可参考http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html W3C specs
      第二个参数是请求页面的URL.由于自身安全特性的限制,该页面不能为第三方域名的页面.同时一定要保证在所有的页面中都使用准确的域名,否则调用open()会得到"permission denied"的错误提示.一个常见的错误是访问站点时使用domain.tld,而当请求页面时,却使用www.domain.tld.
      第三个参数设置请求是否为异步模式.如果是TRUE, JavaScript函数将继续执行,而不等待服务器响应.这就是"AJAX"中的"A".
      如果第一个参数是"POST",send()方法的参数可以是任何想送给服务器的数据. 这时数据要以字符串的形式送给服务器,如下所示:

    name=value&anothername=othervalue&so=on 


    步骤 2 – "收到!" --- 处理服务器的响应

      当发送请求时,要提供指定处理响应的JavaScript函数名.

    http_request.onreadystatechange = nameOfTheFunction; 

      我们来看看这个函数的功能是什么.首先函数会检查请求的状态.如果状态值是4,就意味着一个完整的服务器响应已经收到了,您将可以处理该响应.

    if (http_request.readyState == 4) {
        // everything is good, the response is received
    } else {
        // still not ready
    }

      readyState的取值如下:
      0 (未初始化)
      1 (正在装载)
      2 (装载完毕)
      3 (交互中)
      4 (完成)

      接着,函数会检查HTTP服务器响应的状态值. 完整的状态取值可参见 W3C site. 我们着重看值为200 OK的响应.

    if (http_request.status == 200) {
        // perfect!
    } else {
        // there was a problem with the request,
        // for example the response may be a 404 (Not Found)
        // or 500 (Internal Server Error) response codes
    }

      在检查完请求的状态值和响应的HTTP状态值后, 您就可以处理从服务器得到的数据了.有两种方式可以得到这些数据:

    http_request.responseText – 以文本字符串的方式返回服务器的响应 
    http_request.responseXML – 以XMLDocument对象方式返回响应.处理XMLDocument对象可以用JavaScript DOM函数 


    步骤 3 – "万事俱备!" - 简单实例

      我们现在将整个过程完整地做一次,发送一个简单的HTTP请求. 我们用JavaScript请求一个HTML文件, test.html, 文件的文本内容为"I'm a test.".然后我们"alert()"test.html文件的内容.

    <script type="text/javascript" language="javascript">
        var http_request = false;
        function makeRequest(url) {

            http_request = false;

            if (window.XMLHttpRequest) { // Mozilla, Safari,...
                http_request = new XMLHttpRequest();
                if (http_request.overrideMimeType) {
                    http_request.overrideMimeType('text/xml');
                }
            } else if (window.ActiveXObject) { // IE
                try {
                    http_request = new ActiveXObject("Msxml2.XMLHTTP");
                } catch (e) {
                    try {
                        http_request = new ActiveXObject("Microsoft.XMLHTTP");
                    } catch (e) {}
                }
            }

            if (!http_request) {
                alert('Giving up :( Cannot create an XMLHTTP instance');
                return false;
            }
            http_request.onreadystatechange = alertContents;
            http_request.open('GET', url, true);
            http_request.send(null);

        }

        function alertContents() {

            if (http_request.readyState == 4) {
                if (http_request.status == 200) {
                    alert(http_request.responseText);
                } else {
                    alert('There was a problem with the request.');
                }
            }

        }
    </script>
    <span
        style="cursor: pointer; text-decoration: underline"
        onclick="makeRequest('test.html')">
            Make a request
    </span>


      本例中:
      用户点击浏览器上的"请求"链接;
      接着函数makeRequest()将被调用.其参数 – HTML文件test.html在同一目录下;
      这样就发起了一个请求.onreadystatechange的执行结果会被传送给alertContents();
      alertContents()将检查服务器的响应是否成功地收到,如果是,就会"alert()"test.html文件的内容.

    步骤 4 – "X-文档" --- 处理XML响应

      在前面的例子中,当服务器对HTTP请求的响应被收到后,我们会调用请求对象的reponseText属性.该属性包含了test.html文件的内容.现在我们来试试responseXML属性.

      首先,我们新建一个有效的XML文件,后面我们将使用这个文件.该文件(test.xml)源代码如下所示:

    <?xml version="1.0" ?>
    <root>
        I'm a test.
    </root>

      在该脚本中,我们只需修改请求部分:

    ...
    onclick="makeRequest('test.xml')">
    ...

      接着,在alertContents()中,我们将alert()的代码alert(http_request.responseText);换成:

      var xmldoc = http_request.responseXML;
      var root_node = xmldoc.getElementsByTagName('root').item(0);
      alert(root_node.firstChild.data);
    这里,我们使用了responseXML提供的XMLDocument对象并用DOM方法获取存于XML文件中的内容.

  • 问题一:如果你家附近有一家餐厅,东西又贵又难吃,桌上还爬着蟑螂,你会因为它很近很方便,就一而再、再而三地光临吗? 
    回答:你一定会说,这是什么烂问题,谁那么笨,花钱买罪受?
    可同样的情况换个场合,自己或许就做类似的蠢事。
    不少男女都曾经抱怨过他们的情人或配偶品性不端,三心二意,不负责任。明知在一起没什么好的结果,怨恨已经比爱还多,但却“不知道为什么”还是要和他搅和下去,分不了手。说穿了,只是为了不甘,为了习惯,这不也和光临餐厅一样?
    ——做人,为什么要过于执著?!

    问题二:如果你不小心丢掉100块钱,只知道它好像丢在某个你走过的地方,你会花200块钱的车费去把那100块找回来吗?
    回答:一个超级愚蠢的问题。
    可是,相似的事情却在人生中不断发生。做错了一件事,明知自己有问题,却怎么也不肯认错,反而花加倍的时间来找藉口,让别人对自己的印象大打折扣。被人骂了一句话,却花了无数时间难过,道理相同。为一件事情发火,不惜损人不利已,不惜血本,不惜时间,只为报复,不也一样无聊?
    失去一个人的感情,明知一切已无法挽回,却还是那么伤心,而且一伤心就是好几年,还要借酒浇愁,形销骨立。其实这样一点用也没有,只是损失更多。
    ——做人,干吗为难自己?!



    问题三:你会因为打开报纸发现每天都有车祸,就不敢出门吗? 
    回答:这是个什么烂问题?当然不会,那叫因噎废食。
    而有不少人却曾说:现在的离婚率那么高,让我都不敢谈恋爱了。说得还挺理所当然。也有不少女人看到有关的诸多报道,就对自己的另一半忧心忡忡,这不也是类似的反应?所谓乐观,就是得相信:虽然道路多艰险,我还是那个会平安过马路的人,只要我小心一点,不必害怕过马路。
    ——做人,先要相信自己。


    问题四:你相信每个人随便都可以成功立业吗? 
    回答:当然不会相信。
    但据观察,有人总是在听完成功人士绞尽脑汁的建议,比如说,多读书,多练习之后,问了另一个问题?那不是很难?
    我们都想在3分钟内学好英文,在5分钟内解决所有难题,难道成功是那么容易的吗?改变当然是难的。成功只因不怕困难,所以才能出类拔萃。
    有一次坐在出租车上,听见司机看到自己前后都是高档车,兀自感叹:“唉,为什么别人那么有钱,我的钱这么难赚?”
    我心血来潮,问他:“你认为世上有什么钱是好赚的?”他答不出来,过了半晌才说:好像都是别人的钱比较好赚。
    其实任何一个成功者都是艰辛取得。我们实在不该抱怨命运。
    ——做人,依靠自己!

    问题五:你认为完全没有打过篮球的人,可以当很好的篮球教练吗?
    回答:当然不可能,外行不可能领导内行。
    可是,有许多人,对某个行业完全不了解,只听到那个行业好赚钱,就马上开起业来了。
    我看过对穿着没有任何口味、或根本不在乎穿着的人,梦想却是开间服装店;不知道电脑怎么开机的人,却想在网上聊天,结果道听途说,却不反省自己是否专业能力不足,只抱怨时不我与。
    ——做人,量力而行。

    问题六:相似但不相同的问题:你是否认为,篮球教练不上篮球场,闭着眼睛也可以主导一场完美的胜利? 
    回答:有病啊,当然是不可能的。
    可是却有不少朋友,自己没有时间打理,却拼命投资去开咖啡馆,开餐厅,开自己根本不懂的公司,火烧屁股一样急着把辛苦积攒的积蓄花掉,去当一个稀里糊涂的投资人。亏的总是比赚的多,却觉得自己是因为运气不好,而不是想法出了问题。
    ——做人,记得反省自己。

    问题七:你宁可永远后悔,也不愿意试一试自己能否转败为胜?
    解答:恐怕没有人会说:“对,我就是这样的孬种”吧。
    然而,我们却常常在不该打退堂鼓时拼命打退堂鼓,为了恐惧失败而不敢尝试成功。
    以关颖珊赢得2000年世界花样滑冰冠军时的精彩表现为例:她一心想赢得第一名,然而在最后一场比赛前,她的总积分只排名第三位,在最后的自选曲项目上,她选择了突破,而不是少出错。在4分钟的长曲中,结合了最高难度的三周跳,并且还大胆地连跳了两次。她也可能会败得很难看,但是她毕竟成功了。
    她说:“因为我不想等到失败,才后悔自己还有潜力没发挥。”
    一个中国伟人曾说;胜利的希望和有利情况的恢复,往往产生于再坚持一下的努力之中。
    ——做人,何妨放手一搏。



    问题八:你的时间无限,长生不老,所以最想做的事,应该无限延期?
    回答:不,傻瓜才会这样认为。
    然而我们却常说,等我老了,要去环游世界;等我退休,就要去做想做的事情;等孩子长大了,我就可以……
    我们都以为自己有无限的时间与精力。其实我们可以一步一步实现理想,不必在等待中徒耗生命。如果现在就能一步一步努力接近,我们就不会活了半生,却出现自己最不想看到的结局。
    ——做人,要活在当下。

  • Apache 服务器 Log 分析应用实例
    互联网的飞速发展,无论是传统企业的网站,还是互联网企业,为了了解自己的客户来源,点击率等资料,对网站日志的分析尤为重要,以下就本人所做的日志分析系统与大家分享,希望能对大家有所帮助。

    欢迎大家复制,但请大家保留本文的完整,谢谢!!

    一,所用软件及工具

    1,Apache服务器 官方网址:http://www.apache.org
    2,awstats 日志分析软件 官方网址:http://awstats.sourceforge.net
    3,cronolog 日志截取软件 官方网址:http://www.cronolog.org

    二,环境构架
    ,RedHat AS 3

    2,Apache
    ./configure –prefix=/usr/local/apache2/ --enable-so
    make
    make install

    3, awstats
    直接tar到 /usr/local/awstats

    4,cronolog
    ./configure –prefix=/usr/local/cronolog
    make
    make install

    三, 配置

    1, apache

    a,让apache中的某个虚拟主机产生日志:

    全局环境变量设置:

    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    SetEnvIf Request_URI \.gif$ gif-image
    SetEnvIf Request_URI \.GIF$ gif-image
    SetEnvIf Request_URI \.jpg$ gif-image
    SetEnvIf Request_URI \.JPG$ gif-image
    SetEnvIf Request_URI \.png$ gif-image
    SetEnvIf Request_URI \.swf$ gif-image
    SetEnvIf Request_URI \.SWF$ gif-image
    SetEnvIf Request_URI \.css$ gif-image
    SetEnvIf Request_URI \.CSS$ gif-image
    SetEnvIf Request_URI \.js$ gif-image
    SetEnvIf Request_URI \.JS$ gif-image
    SetEnvIf Request_URI \.ico$ gif-image

    产生日志但不包括图片。
    虚拟主机日志设置

    <VirtualHost 12.34.56.78:80>
            ServerAdmin webmaster@abc.net
            DocumentRoot /db/htdocs/www
            ServerName www.abc.net
            CustomLog "|/usr/local/cronolog/sbin/cronolog /db/logs/www.%Y-%m-%d.log" combined env=!gif-image
    #用cronolog截取存放在/db/logs/下的按日期产生的apache日志文件
    </VirtualHost>

    注:日志文件是针对每一个虚拟主机产生的所以可以配置一台服务器上多个虚拟主机的日志分析

    b,别名设置

    #
    # Directives to allow use of AWStats as a CGI
    #
    Alias /awstatsclasses "/usr/local/awstats/wwwroot/classes/"
    Alias /awstatscss "/usr/local/awstats/wwwroot/css/"
    Alias /awstatsicons "/usr/local/awstats/wwwroot/icon/"
    ScriptAlias /awstats/ "/usr/local/awstats/wwwroot/cgi-bin/"

    #
    # This is to permit URL access to scripts/files in AWStats directory.
    #
    <Directory "/usr/local/awstats/wwwroot">
        Options None
        AllowOverride None
        Order allow,deny
        Allow from all
    </Directory>


    该配置在运行awstats/tools/awstats_configure.pl 后会自动产生所以不用手动添加。

    c,awstats需要cgi的支持如果没有添加cgi可以现在添加

    ./apxs -c -i /usr/local/src/httpd-2.0.50/modules/generators/mod_cgi.c


    再在httpd.conf 中添加

    LoadModule cgi_module         modules/mod_cgi.so


    d为了保护日志统计信息需要对某些目录进行认证设置,需要认证模块的支持

    ./apxs -c -i /usr/local/src/httpd-2.0.50/..../mod_auth.c


    再在httpd.conf 中添加

    LoadModule auth_module        modules/mod_auth.so


    配置需要认证的目录:

    <Directory "/db/htdocs/www/awstat/">
       AuthType Basic
      AuthName "Restricted Files"
      AuthUserFile /usr/local/apache2/passwd/passwords
      Require user loguser
      </Directory>


    其中在 /usr/local/apache2/passwd/下产生passwords 的密码文件
    运行如下代码产生用户名为loguser用户及其密码

    /usr/local/apache2/bin/htpasswd -c /usr/local/apache2/passwd/passwords  loguser


    注意:先要在 /usr/local/apache2/下建passwd目录

    2,Awstats

    运行 /usr/local/awstats/tools/awstats_configure.pl
    主要设置的是需要输入做统计的主机名的配置文件名如:www.abc.net
    接着修改 刚才配置是产生的awstats配置文件 默认位置在:
    /etc/awstats/awstats.www.abc.net.con 主要做指定log位置

    LogFile="/db/logs/www.%YYYY-4-%MM-2-%DD-2.log"


    创建目录:mkdir /var/lib/awstats/
    执行:

    /usr/local/awstats/wwwroot/cgi-bin/awstats.pl -update -config=www.abc.net


    更新,update 后可以在浏览器中输入 http://www.abc.net/awstats/awstats.pl 进行访问了。

    3,cronolog (基本不用什么修改)

    4,crontab的修改

    在 crontab中添加如下 命令保证15分钟更新一次,也可以根据你自己的需要修改更新的间隔

    */15 * * * * /usr/local/awstats/wwwroot/cgi-bin/awstats.pl -update -config=www.abc.net


    四,安全性考虑

    1, 以上的设置由于要cgi支持,也增加了安全隐患可以用awstats 自带的awstats_buildstaticpages.pl来 生成静态页面 可以添加到crontab中

    */15 * * * * /usr/local/awstats/tools/awstats_buildstaticpages.pl -update -config=www.abc.net -lang=cn -dir=/db/htdocs/www/awstat/ -awstatsprog=/usr/local/awstats/wwwroot/cgi-bin/awstats.pl


    这样没15分钟在/db/htdocs/www/awstat/ 下生成各种静态页面

    2,保护/db/htdocs/www/awstat/禁止未授权用户访问

    在httpd.conf中添加

    <Directory "/db/htdocs/www/awstat/">
      AuthType Basic
    AuthName "Restricted Files"
      AuthUserFile /usr/local/apache2/passwd/passwords
       Require user loguser
      </Directory>


    如果www.abc.net 虚拟主机 主目录为/db/htdocs/www/ 则在浏览器中输入http://www.abc.net/awstat/awstats.www.abc.net.html 就可以通过认真访问静态页面

    3,如果用静态页面就不要忘了注释掉

    LoadModule cgi_module modules/mod_cgi.so
  • AWStats是sourceforge.net上很有名的Web/Mail/FTP服务器日志文件分析工具。
    安装配置步骤(适用于分析IIS日志文件)
    1、下载AWStats, 下载地址:http://sourceforge.net/projects/awstats/
    2、由于AWStats是Pertl写的,所以要下载Perl 解释器, 下载地址: http://activestate.com/Products/ActivePerl/
    3、安装Perl 解释器ActivePerl
    4、安装AWStats(这里假设安装在C:\Program Files), 出现命令提示时,第一次输入none, 第二次输入你的主机的域名
    5、配置IIS日志
          5.1 活动日志格式选用默认的“W3C扩充扩展日志文件格式”
          5.2 点击“属性”,再选择“扩展属性”,选中下列项目:
         date
         time
         c-ip
         cs-username
         cs-method
         cs-uri-stem
         cs-uri-query
         sc-status
         sc-bytes
         cs-version
         cs(User-Agent)
         cs(Referer)
         其他都不要选中。
    6、建立虚拟目录cgi-bin,映射到C:\Program Files\AWStats\wwwroot\cgi-bin。
          建立虚拟目录ico, 映射到C:\Program Files\AWStats\wwwroot\icon
    7、修改C:\Program Files\AWStats\wwwroot\cgi-bin中的相应的配置文件:awstats.myvirtualhostname.conf(myvirtualhostname为你第4步中输入的域名, 比如www.cnblogs.com)。修改下列项目:

    LogFile="C:\WINDOWS\System32\LogFiles\W3SVC1\ex%YY-0%MM-0%DD-0.log" 
    LogFormat
    ="date time c-ip cs-username cs-method cs-uri-stem cs-uri-query sc-status sc-bytes cs-version cs(User-Agent) cs(Referer)" 
    AllowToUpdateStatsFromBrowser
    =1 
    LoadPlugin
    ="timezone +8" 

    8、重启IIS, 删除C:\WINDOWS\System32\LogFiles\W3SVC1下的所有日志文件
    9、使配置生效: awstats.pl -config=myvirtualhostname -update
    10、配置完成,通过Web访问日志http://www.myserver.mydomain/cgi-bin/awstats.pl?config=myvirtualhostname,点击“立即更新”。
    页面截图:

    11、通过任务计划自动更新:
           创建批处理文件AwstatsUpate.bat,内容为 :

    c:
    cd C:\Program Files\AWStats\wwwroot\cgi
    -bin
    awstats.pl 
    -config=www.cnblogs.com -update

        
         在任务计划调度运行该批处理文件。
       
    更详细的步骤,请查看帮助文件C:\Program Files\AWStats\docs\awstats_setup.html
    参考文章:
        1、http://briandesmond.com/blog/archive/2003/09/08/176.aspx
        2、http://www.cnblogs.com/Files/dudu/InstallingAWStatsOnIIS6.rar(pdf文件)

  • 2005-10-12

    容错wget脚本

    #!/bin/sh url=$1   #要抓取的网页地址
    minsize=$2  #最小的文件大小
    bakname=$3  #临时文件名
    filename=$4  #目标文件名
    checkerror="is"$5 #是否检查服务器内部错误 expression="500 Servlet Exception" /usr/bin/wget ${url} -O ${bakname}
    bsize=`ls -l ${bakname} | awk '{if ($5 > '$minsize') print "true"; else print "false" }'` if (test $checkerror = "istrue")
    then
      count=`/bin/grep -P -c "${expression}" ${bakname}`
      if (test $count != "0")
      then
       
        bsize="false"
      fi
    fi
    if (test $bsize = "true")
    then
       /bin/cp ${bakname} ${filename}
    fi
  • apache访问日志里面的中文有两种编码

    比如访问包含了"木子美"的url就会产生

    \xc4\xbe\xd7\xd3\xc3\xc0

    %E6%9C%A8%E5%AD%90%E7%BE%8E

    两种,根据不同浏览器或版本或是搜索引擎等

    第一种解码方法:

    把\x替换为%,则变为

    s = "%c4%be%d7%d3%c3%c0"

    然后用gb2312的url解码

    s = URLDecoder.decode(s,"gb2312");

    第二种简单点,直接用utf-8解码就行了

    s = "%E6%9C%A8%E5%AD%90%E7%BE%8E"

    s = URLDecoder.decode(s,"utf-8");

  • 昨晚服务器上的resin就起不来,登录服务器看看,发现以下出错信息:

    Specification version 1.3 of package javax.servlet, J2EE Specification, version 1.3 is not compatible with Resin Resin-3.0.x. Resin-3.0.x requires version 2.4.

    google下找到

    http://www.caucho.com/resin-3.0/troubleshoot/common-problems.xtp#Specification-version-1.3-of-package-javax.servlet,-J2EE-Specification,-version-1.3-is-not-compatible-with-Resin-Resin-3.0.x.-Resin-3.0.x-requires-version-2.4.

    官方的解决方案是:

    This error occurs when you have an old or conflicting jar containing the servlet api in your CLASSPATH. The solution is to clean up your classpath .

    我重点检查了下servlet.jar; j2ee.jar  发现 classpath有j2ee.jar ,估计里面的servlet版本过低,在classpath去掉 j2ee.jar,重新启动,问题解决;