<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>sorphi</title>
    <description>沉默的时候我感到充实，我将开口，同时感到空虚。</description>
    <link>http://sorphi.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>SNA方案之session store调研</title>
        <author>sorphi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://sorphi.javaeye.com">sorphi</a>&nbsp;
          链接：<a href="http://sorphi.javaeye.com/blog/200611" style="color:red;">http://sorphi.javaeye.com/blog/200611</a>&nbsp;
          发表时间: 2008年06月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>SNA方案中，session的存放是一个重要方面。javaeye中提出的解决方案主要基于memcached：</p>
<p>&nbsp;</p>
<p>codeutil通过hack tomcat6的session manage相关类<a href="../../../../topic/81641" target="_blank">将标准的servlet session存储在memcached中</a>。该hack解决了一部分问题，但是最终没有完全绕过ManagerBase中的sessions实例和StandardSession中的attributes实例。从代码上看，群集环境中，存在着各个JVM中的sessions实例和attributes实例无法与memcached保持同步的问题，继而隐藏着session dirty或者expire机制失效的BUG。</p>
<p>&nbsp;</p>
<p>另外一种方案是自定义Map&lt;String,Map&lt;String,Serializable&gt;&gt;来取代servlet容器的SessionStore机制。使用memcached作为underlying store的，仍然需要解决session expire的问题。关于memcached管理session expire的问题，balaschen等<a href="../../../../topic/84142" target="_blank">hack了memcached的代码</a>。每次get操作的时候更新expire值，继而试图让memcached自行管理。这种方案限于每个session只能作为一个key/value pair存放于memcached。而通常更有效的存储结构是：</p>
<p>sessionkey:["attr1","attr2","access_timestamp"]</p>
<p>sessionkey_attr1:{}</p>
<p>sessionkey_attr2:{}</p>
<p>&nbsp;</p>
<p>ROR社区使用cookie_store，很好。虽然没有看过其实现机制，但是以java的实现该是这样：</p>
<p>new ObjectOutputStream(new GZIPOutputStream(new CipherInputStream(new Base64OutputStream(out),cipher))).writeObject(state);</p>
<p>&nbsp;</p>
<p>我个人感觉cookie item 4k的容量，存放压缩过的信息已经足够了。关于session中应该/不应该存放什么的讨论，javaeye有很多。我个人总结是，session中存放用户与服务端资源交互产生的、无法由服务端自行决定存放的状态信息。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>如果仍然需要session_store的话，我还是更倾向于自定义session结构这种方案。虽然丧失了一部分容器session 机制的好处(比如event，标准接口)，但是可以免去hack的痛苦，且与容器无关，轻量级。使用<a href="../../../../news/1617" target="_blank">dbcached(memcached+nmdb+qdbm)</a>来作为underlying store，增加了持久、故障转移等功能。</p>
<p>&nbsp;</p>
<p>但是，session iterate仍然是待解决的问题。</p>
<p>&nbsp;</p>
<p>为什么需要iterate？可以更加灵活的进行expire，还有在线人数统计这类常见的需求。</p>
<p>&nbsp;</p>
<p>虽然qdbm提供的java client中Villa可以按照key的前缀进行iterate，但是client无法使用nmdb独占打开的那个db，而nmdb又没有提供java client，更沮丧的是其client规范中规定的可操作方法并没有iterate。目前正在调研其他解决方案。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>还有基于terracotta的<a href="../../../../topic/88466" target="_blank">JVM-level clustering来管理session</a>。很重量级，这里不表。</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://sorphi.javaeye.com/blog/200611#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 05 Jun 2008 17:40:47 +0800</pubDate>
        <link>http://sorphi.javaeye.com/blog/200611</link>
        <guid>http://sorphi.javaeye.com/blog/200611</guid>
      </item>
      <item>
        <title>heartbeat V2在CentOS4.6上简要安装、配置笔记</title>
        <author>sorphi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://sorphi.javaeye.com">sorphi</a>&nbsp;
          链接：<a href="http://sorphi.javaeye.com/blog/191076" style="color:red;">http://sorphi.javaeye.com/blog/191076</a>&nbsp;
          发表时间: 2008年05月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>heartbeat V2在CentOS4.6上简要安装、配置笔记</p>
<p>（shell行命令用粗体表示）</p>
<h4>一、准备工作</h4>
<p>1、环境<br />
两台CentOS4.6，各一个网卡，IP地址分别为192.168.0.1和192.168.0.2<br />
<br />
<strong>uname -n</strong>
<br />
分别显示node1和node2<br />
<br />
<strong>cat /etc/hosts</strong>
<br />
均显示<br />
127.0.0.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; localhost.localdomain&nbsp;&nbsp; localhost<br />
192.168.0.1 node1<br />
192.168.0.2 node2<br />
<br />
<br />
2、两个node分别安装libnet<br />
hearbeat默认编译选项需要e2fsprogs/libnet库，CentOS4.6默认安装了e2fsprogs，所以这里先安装libnet<br />
<br />
<strong>cd /usr/local/src<br />
wget http://www.packetfactory.net/libnet/dist/libnet.tar.gz<br />
tar zxvf libnet.tar.gz<br />
cd libnet<br />
./configure<br />
make &amp;&amp; make install</strong>
<br />
<br />
3、两个node分别创建heartbeat相关的用户和组<br />
<strong>groupadd haclient<br />
useradd -g haclient hacluster</strong>
<br />
<br />
4、关闭两个node上的防火墙（如SELINUX），或者设置为信任eth0，使得能相互听见对方心跳。否则两个node都认为对方的状态为dead。（我在这个问题上折腾了一会。其他如采用双绞线通过串口进行心跳监控之类的方案也必须检查双绞线是否正常，保证线路通畅。）<br />
<br /></p>
<h4>二、两个node分别下载、编译、安装heartbeat</h4>
<p><strong>cd /usr/local/src<br />
wget http://linux-ha.org/download/heartbeat-2.1.3.tar.gz<br />
tar zxvf heartbeat-2.1.3.tar.gz<br />
cd heartbeat-2.1.3<br />
./ConfigureMe configure</strong>
<br />
<br />
大致看看编译统计信息后安装<br />
<br />
<strong>make &amp;&amp; make install</strong>
<br />
<br /></p>
<h4>三、在node1上的简易配置</h4>
<p>将配置文件模板拷贝到默认配置目录（可选，也可手工创建。模板文件中的注释可帮助你理解各配置选项的含义）<br />
<br />
<strong>cp doc/authkeys /etc/ha.d/<br />
cp doc/ha.cf /etc/ha.d/<br />
<br />
<br />
cd /etc/ha.d/</strong>
<br />
<br />
开始编辑配置文件（两台机器上都需要安装和配置）<br />
1、编辑/etc/ha.d/authkeys，使用的是第1种认证方式(crc)，接着把文件的权限改为600：<br />
<strong>cat /etc/ha.d/authkeys</strong>
<br />
显示<br />
auth 1<br />
1 crc<br />
<br />
更改文件权限<br />
<strong>chmod 600 /etc/ha.d/authkeys</strong>
<br />
<br />
关于<a href="http://linux-ha.org/authkeys" target="_blank">Configuring authkeys</a>
<br />
<br />
2、编辑/etc/ha.d/ha.cf：<br />
<strong>cat /etc/ha.d/ha.cf | grep -v '#'</strong>
<br />
文件显示如下<br />
keepalive 10<br />
deadtime 60<br />
warntime 20<br />
initdead 60<br />
udpport 694<br />
mcast eth0 225.0.0.1 694 1 0<br />
watchdog /dev/watchdog<br />
node node1 node2<br />
ping 192.168.0.254<br />
use_logd yes<br />
compression&nbsp;&nbsp;&nbsp;&nbsp; zlib<br />
traditional_compression false<br />
crm on<br />
autojoin any<br />
<br />
关于<a href="http://linux-ha.org/ha.cf" target="_blank">ha.cf的指令说明</a>
<br />
<br />
注意：<br />
ping 192.168.0.254<br />
ping网关，使得每个节点得知自己是否已经离线。我尝试去掉该选项的结果是：当node1拔掉网线之后，node2接管了资源。再插上node1的网线，node2的日志中会不停的出现&ldquo;WARN: crmd_ha_msg_callback&rdquo;信息（不信可以试试）。<br />
<br />
<a href="http://linux-ha.org/GettingStartedV2#head-d974b71a398e73a8cc9a31de39000fb0213449f0" target="_blank">Additional Options</a>
 应该是V2中用来监控Heartbeat运行时对cib.xml的修改。除调试外感觉没啥用，日志中新增了一堆diff信息。<br />
# apiauth cibmon&nbsp;&nbsp; uid=hacluster<br />
# respawn hacluster /usr/lib/heartbeat/cibmon -d<br />
<br />
<br />
3、资源文件配置。这里以<a href="http://linux-ha.org/GettingStartedV2/TwoApaches" target="_blank">Two Apache Web Servers in an Active/Active Configuration</a>
的更改版(Two Nginx Web Servers in an Active/Active Configuration)来举例。编辑/etc/ha.d/haresources（V1）或者/var/lib/heartbeat/crm/cib.xml（V2）<br />
cib.xml对于初学者来说很难编写，官方的例子中不能简单的拷贝过来，贸然运行heartbeat会导致node重启，我猜测的原因是官方的示例并未遵循<a href="http://hg.clusterlabs.org/pacemaker/dev/file/tip/xml/crm-1.0.dtd" target="_blank">其DTD</a>
。<br />
<br />
简单的方法是采用hearbeat提供的工具将V1方式的资源配置文件转换为V2 style的。比如：<br />
<br />
<strong>cat /tmp/haresources</strong>
<br />
文件内容显示为：<br />
node1 192.168.0.3 nginx<br />
node2 192.168.0.4 nginx<br />
<br />
意思是，优先在node1上绑定192.168.0.3这个虚拟IP，并管理(start/stop/status)本机上的nginx。优先在node2上绑定192.168.0.4这个虚拟IP，并管理本机上的nginx。<br />
<br />
这里nginx是一个LSB style脚本，位于/etc/init.d/nginx，示例可见<a href="190257" target="_blank">这里</a>
。先保证nginx已经安装到两个node上了。<br />
<br />
转换命令<br />
<strong>/usr/lib/heartbeat/haresources2cib.py --stout -c /etc/ha.d/ha.cf /tmp/haresources</strong>
<br />
<br />
运行转换命令之后，/var/lib/heartbeat/crm/cib.xml自动产生。（请在熟悉了hearbeat之后再去尝试修改该文件。）<br />
<br /></p>
<h4>四、将node1上的heartbeat相关的配置文件拷贝到node2</h4>
<p><strong>scp /etc/ha.d/ha.cf root@node2:/etc/ha.d/ha.cf<br />
scp /etc/ha.d/authkeys root@node2:/etc/ha.d/authkeys<br />
scp /var/lib/heartbeat/crm/cib.xml root@node2:/var/lib/heartbeat/crm/cib.xml</strong>
<br />
<br />
请确保两个node上的配置文件内容和权限相同。<br />
<br /></p>
<h4>五、在两个node上启动heartbeat并观察结果</h4>
<p><br />
1、修改两个node上nginx的index.html<br />
在node1上：<br />
<strong>echo 'node1 welcome!' &gt; /usr/local/nginx/html/index.html</strong>
<br />
在node1上：<br />
<strong>echo 'node2 welcome!' &gt; /usr/local/nginx/html/index.html</strong>
<br />
<br />
2、启动两个node上的heartbeat，然后稍等片刻（时间长短取决于ha.cf中的相关参数）。<br />
<strong>/etc/init.d/heartbeat start</strong>
<br />
<br />
<br />
按照我这里的ha.cf配置，日志信息应该可以通过<br />
<strong>tail /var/log/messages -f</strong>
<br />
进行查看<br />
<br />
3、在两个node上分别运行<strong>ifconfig</strong>
和<strong>ps -ef</strong>
来查看虚拟IP和ngnix是否已经启动。<br />
<br />
4、在浏览器中分别访问http://192.168.0.3/和http://192.168.0.4/，观察。<br />
<br />
5、将node1从局域网中断开，稍等片刻。再重复上面的步骤3、4，观察。<br />
<br />
6、将node1重新接入局域网，稍等片刻。再重复上面的步骤3、4，观察。<br />
<br />
<br />
相信你的第一个示例成功之后，对heartbeat的基础原理应该有所了解。接着再详细查看官方文档和网络资料，结合实际进行特定服务的HA，多试验、多失败、多研究。<br />
<br />
主要参考资料：<br />
<a href="http://linux-ha.org/" target="_blank">官方网站</a>
中的文档<br />
<a href="http://linux.chinaunix.net/bbs/forum-9-1.html" target="_blank">CU集群和虚拟机论坛</a>
中相关线索<br /></p>
          <br/>
          <span style="color:red;">
            <a href="http://sorphi.javaeye.com/blog/191076#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 08 May 2008 14:44:29 +0800</pubDate>
        <link>http://sorphi.javaeye.com/blog/191076</link>
        <guid>http://sorphi.javaeye.com/blog/191076</guid>
      </item>
      <item>
        <title>/etc/init.d/nginx (lsb style)</title>
        <author>sorphi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://sorphi.javaeye.com">sorphi</a>&nbsp;
          链接：<a href="http://sorphi.javaeye.com/blog/190257" style="color:red;">http://sorphi.javaeye.com/blog/190257</a>&nbsp;
          发表时间: 2008年05月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>这几天学习了一下heartbeat的资料，想参照 <a href="http://linux-ha.org/GettingStartedV2/TwoApaches" target="_blank">Two Apache Web Servers in an Active/Active Configuration</a>
&nbsp;&nbsp; 做个Two Nginx Web Services in Active/Active HA。研究发现，heartbeat所管理的资源代理(Resource Agent)，有<a href="http://www.alidba.net/index.php/archives/66" target="_blank">OCF、LSB等几种</a>
。LSB这种shell脚本我还能依葫芦画瓢的写一点，参考linux系统中的原有脚本和网上资料，写了一个很简单的：</p>
<p>&nbsp;</p>
<pre name="code" class="c">#!/bin/bash
#
# nginx:       Control the nginx Daemon
#
# Version:      @(#) /etc/init.d/nginx 0.1
#
# description: This is a init.d script for nginx. Tested on CentOS4. \
#              Change DAEMON and PIDFILE if neccessary.
#

#Location of nginx binary. Change path as neccessary
DAEMON=/usr/local/nginx/sbin/nginx
NAME=`basename $DAEMON`

#Pid file of nginx, should be matched with pid directive in nginx config file.
PIDFILE=/var/run/$NAME.pid

#this file location
SCRIPTNAME=/etc/init.d/$NAME

#only run if binary can be found
test -x $DAEMON || exit 0

RETVAL=0

start() {
	echo $&quot;Starting $NAME&quot;
	$DAEMON
	RETVAL=0
}

stop() {
	echo $&quot;Graceful stopping $NAME&quot;
	[ -s &quot;$PIDFILE&quot; ] &amp;&amp; kill -QUIT `cat $PIDFILE`
	RETVAL=0
}

forcestop() {
    echo $&quot;Quick stopping $NAME&quot;
    [ -s &quot;$PIDFILE&quot; ] &amp;&amp; kill -TERM `cat $PIDFILE`
    RETVAL=$?
}

reload() {
    echo $&quot;Graceful reloading $NAME configuration&quot;
    [ -s &quot;$PIDFILE&quot; ] &amp;&amp; kill -HUP `cat $PIDFILE`
    RETVAL=$?
}

status() {
    if [ -s $PIDFILE ]; then
        echo $&quot;$NAME is running.&quot;
        RETVAL=0
    else
        echo $&quot;$NAME stopped.&quot;
        RETVAL=3
    fi
}
# See how we were called.
case &quot;$1&quot; in
    start)
        start
        ;;
    stop)
        stop
        ;;
    force-stop)
        forcestop
        ;;
    restart)
        stop
        start
        ;;
    reload)
        reload
        ;;
    status)
        status
        ;;
    *)
        echo $&quot;Usage: $0 {start|stop|force-stop|restart|reload|status}&quot;
        exit 1
esac

exit $RETVAL
</pre>
<p>注意对应的Nginx配置的PID指令。</p>
<p>参考资料：</p>
<p><a href="http://linux-ha.org/LSBResourceAgent" target="_blank">LSBResourceAgent</a>
</p>
<p><a href="http://wiki.codemongers.com/NginxCommandLine" target="_blank">Running and Controlling Nginx</a>
 </p>
<h4><a href="http://www.feldpost.com/2007/1/21/boot-script-for-nginx-on-ubuntu-debian-etc" target="_blank">Boot Script for Nginx on Ubuntu, Debian etc.</a>
</h4>
          <br/>
          <span style="color:red;">
            <a href="http://sorphi.javaeye.com/blog/190257#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 06 May 2008 15:42:35 +0800</pubDate>
        <link>http://sorphi.javaeye.com/blog/190257</link>
        <guid>http://sorphi.javaeye.com/blog/190257</guid>
      </item>
      <item>
        <title>老版本apache模拟2.2.5中出现的ProxyPassMatch</title>
        <author>sorphi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://sorphi.javaeye.com">sorphi</a>&nbsp;
          链接：<a href="http://sorphi.javaeye.com/blog/177876" style="color:red;">http://sorphi.javaeye.com/blog/177876</a>&nbsp;
          发表时间: 2008年03月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>反向代理是webserver和appserver结合的通用解决方案。apache提供了mod_proxy,mod_proxy_ajp来干这个事情。另外还有应用服务器方提供的mod比如mod_jk，mod_wl等。<br /><br />使用mod_jk的同学估计对ajp又爱又恨吧？因为ajp不支持regex方式来代理动态请求。其实关于各种反向代理模块，配置的灵活性、性能，都是需要权衡的。不使用mod_jk的同学又希望有一款模块能够灵活的配置，现在apache2.2.5给mod_proxy新增了一个<a href="http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxypassmatch" target="_blank">ProxyPassMatch</a>指令，可以试试。</p><p>&nbsp;</p><p>这篇文章主要是给那些暂时不能使用apache2.2.5的同学看的。估计很多人应该知道mod_rewrite中的RewriteRule指令中[P]标识，是用来加强ProxyPass的。但是rewrite拍脑袋想一下应该是对webserver有性能上的消耗的。这里我试图给出一个目前我能想到的最灵活也兼顾性能的配置方案：</p><p>&nbsp;</p><p>&nbsp;</p><pre name="code" class="java">#global disable rewrite
RewriteEngine off

&lt;LocationMatch &quot;^/context/(.*)\.(jsp|action|do)$&quot;&gt;
        #per-dir enable rewrite
        Options +FollowSymLinks
        RewriteEngine on
        RewriteRule ^/YourWebserverDocumentRoot/(.*) http://appserver:port/$1 [P,QSA,L]
&lt;/LocationMatch&gt;</pre>&nbsp;<p>&nbsp;</p><p>&nbsp;</p><p>只是，apache文档中说：</p><p>Although rewrite rules are syntactically permitted in <a href="http://httpd.apache.org/docs/2.2/mod/core.html#location">&lt;Location&gt;</a> sections, this
should never be necessary and is unsupported.</p><p>&nbsp;</p><p>有谁能够给我解惑？我现在只能假设，对于每一个请求，LocationMatch匹配是快于RewriteRule匹配的。但能想象，上面这个配置，若匹配到URI，至少有两次匹配过程。有时间做一个测试来验证。</p><p>&nbsp;</p><p>我其实并不推崇这种rewrite的技巧，同时也对java web应用的特定扩展名感到厌烦了。如果能够更合理的组织URI，ajp肯定是更合理的方案。</p>
          <br/>
          <span style="color:red;">
            <a href="http://sorphi.javaeye.com/blog/177876#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 30 Mar 2008 23:38:59 +0800</pubDate>
        <link>http://sorphi.javaeye.com/blog/177876</link>
        <guid>http://sorphi.javaeye.com/blog/177876</guid>
      </item>
      <item>
        <title>获取form post的charset【改造版】</title>
        <author>sorphi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://sorphi.javaeye.com">sorphi</a>&nbsp;
          链接：<a href="http://sorphi.javaeye.com/blog/177716" style="color:red;">http://sorphi.javaeye.com/blog/177716</a>&nbsp;
          发表时间: 2008年03月30日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <a href="../../blog/177621" target="_blank">前面</a>提到过我的一个低级失误并对servlet的setCharacterEncoding有了正确认识。<p>&nbsp;</p><p>主要是基于这么一个思路解决我的问题：&nbsp;</p><br /><pre name="code" class="html">&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=gbk&quot;/&gt;
...

&lt;form method=&quot;post&quot; action=&quot;/servlet&quot; accept-charset=&quot;utf-8&quot;&gt;
&lt;input type=&quot;hidden&quot; name=&quot;_charset_&quot;/&gt;
&lt;input type=&quot;text&quot; name=&quot;text&quot;/&gt;
&lt;input type=&quot;submit&quot; value=&quot;Submit&quot;/&gt;
&lt;/form&gt;

</pre>&nbsp;&nbsp;<p>&nbsp;</p><p>&nbsp;</p><p>这个表单配合原来在weblogic下写的filter代码，在IE和firefox下运行正常。但既然遵循servlet规范，不能在filter中通过_charset_这个request参数来获取浏览器对post body的真实编码，只能想点歪门邪道了。向jsessionid取经，这个表单改成这样：（关于URL中的分号，请参考RFC1738，这里有个<a href="http://man.chinaunix.net/develop/rfc/RFC1738.txt" target="_blank">中文版</a>）</p><p>&nbsp;</p><pre name="code" class="html">&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=gbk&quot;/&gt;

...
&lt;form method=&quot;post&quot; action=&quot;/servlet;_charset_=utf-8&quot; accept-charset=&quot;utf-8&quot;&gt;
&lt;input type=&quot;hidden&quot; name=&quot;_charset_&quot;/&gt;
&lt;input type=&quot;text&quot; name=&quot;text&quot;/&gt;
&lt;input type=&quot;submit&quot; value=&quot;Submit&quot;/&gt;
&lt;/form&gt;

</pre>&nbsp;<p>&nbsp;</p><p>&nbsp;</p>
<p>&nbsp;filter的改造就略了，无非是hack下request uri。幸好遗留应用并不需要url中重写jsessionid。<img title="wink" src="../../images/smiles/icon_wink.gif" border="0" alt="wink" /></p><p>&nbsp;</p><p>测试，运行，firefox正常了，IE又不正常。哦，恍然大雾啊，原来firefox是严格的根据accept-charset来编码，若accept-charset不存在，则按response或者meta http-equiv=&quot;Content-Type&quot;中的声明来编码，最后把编码方式放到_charset_隐藏域。而IE还是顽固的只按照response或者meta http-equiv=&quot;Content-Type&quot;中的声明来编码，并把编码方式放到_charset_隐藏域。原来IE无视accept-charset的存在。我原先一直以为_charset_隐藏域只是IE对accept-charset的一个强制辅助呢，又一个一知半解的典型...</p><p>&nbsp;</p><p>得了，只能让firefox和IE同流合污了。最终，表单变成这样：</p><p>&nbsp;</p><pre name="code" class="html">&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=gbk&quot;/&gt;

...
&lt;form method=&quot;post&quot; action=&quot;/servlet;_charset_=gbk&quot;&gt;
&lt;input type=&quot;text&quot; name=&quot;text&quot;/&gt;
&lt;input type=&quot;submit&quot; value=&quot;Submit&quot;/&gt;
&lt;/form&gt;</pre><p>&nbsp;</p><p>在IE和firefox下均测试通过。</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://sorphi.javaeye.com/blog/177716#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 30 Mar 2008 02:44:08 +0800</pubDate>
        <link>http://sorphi.javaeye.com/blog/177716</link>
        <guid>http://sorphi.javaeye.com/blog/177716</guid>
      </item>
      <item>
        <title>将应用从weblogic移植到tomcat时学习了一个servlet规范</title>
        <author>sorphi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://sorphi.javaeye.com">sorphi</a>&nbsp;
          链接：<a href="http://sorphi.javaeye.com/blog/177621" style="color:red;">http://sorphi.javaeye.com/blog/177621</a>&nbsp;
          发表时间: 2008年03月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          一个遗留web网页(gbk编码)需要POST方式请求一个servlet应用(utf-8)， 得写一个filter进行转码。关于form表单提交的编码问题，可以参考这个：<a href="http://www.jsfsoft.com:8080/beyond-pebble/pinxue/2006/07/27/1153934754918.html" target="_blank">Java Web应用的form文字编码问题</a>，或者<a href="http://www.blogjava.net/emu/archive/2008/01/31/178715.html" target="_blank">在IE下面指定表单编码方式</a>。<br /><p>&nbsp;</p><p>参照上面的第一个文档，这个filter很好写：</p><p>&nbsp;</p><pre name="code" class="java">public void doFilter(ServletRequest servletRequest,
                       ServletResponse servletResponse,
                       FilterChain filterChain) throws
      IOException, ServletException {
    if(servletRequest.getCharacterEncoding()==null){
      String encoding = servletRequest.getParameter(&quot;_charset_&quot;);
      if(encoding == null){
        encoding = _defaultEncoding;
      }
      if (encoding != null) {
        servletRequest.setCharacterEncoding(encoding);
        if(LOG.isDebugEnabled()){
          LOG.debug(&quot;Set request encoding to:&quot;+encoding);
        }
      }
    }
    filterChain.doFilter(servletRequest, servletResponse);
  }</pre>&nbsp;<p>&nbsp;</p><p>&nbsp;</p><p>这段代码在weblogic8下面应用良好，gbk编码的网页很好的提交到一个utf-8编码的servlet应用，没有其他的额外转码工作。</p><p>&nbsp;</p><p>当移植到tomcat6下面时，乱码问题出现了。即使通过一个utf-8编码的网页来提交依然乱码，request中的数据是iso-8859-1编码。很久没有碰到过乱码问题了，于是我又不自信起来，找了每个环节的问题。最后终于发现是这个filter没有遵循一个servlet规范，ServletRequest的文档中说：</p><h3>setCharacterEncoding</h3>
<pre>public void <strong>setCharacterEncoding</strong>(java.lang.String&nbsp;env)
                          throws java.io.UnsupportedEncodingException</pre>
<dl><dd>Overrides the name of the character encoding used in the body of this
 request. This method must be called prior to reading request parameters
 or reading input using getReader().</dd><dd><dl><dt><strong>Parameters:</strong></dt><dd>a - String containing the name of 
			the chararacter encoding.</dd><dt><strong>Throws:</strong></dt><dd>java.io.UnsupportedEncodingException - if this is not a valid encoding</dd></dl>
</dd></dl><p>&nbsp;</p><p>我错了，光看方法名字就开练，api文档看得不够仔细。在这次迁移工作中，学了这么一个servlet规范。</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://sorphi.javaeye.com/blog/177621#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 29 Mar 2008 16:58:31 +0800</pubDate>
        <link>http://sorphi.javaeye.com/blog/177621</link>
        <guid>http://sorphi.javaeye.com/blog/177621</guid>
      </item>
      <item>
        <title>Drop-in WLS Replicated Session Replacement</title>
        <author>sorphi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://sorphi.javaeye.com">sorphi</a>&nbsp;
          链接：<a href="http://sorphi.javaeye.com/blog/35391" style="color:red;">http://sorphi.javaeye.com/blog/35391</a>&nbsp;
          发表时间: 2006年11月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <a href="http://blog.terracottatech.com/archive/2005/08/drop-in_wls_rep.html">Drop-in WLS Replicated Session Replacement</a>
          <br/>
          <span style="color:red;">
            <a href="http://sorphi.javaeye.com/blog/35391#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 21 Nov 2006 18:12:30 +0800</pubDate>
        <link>http://sorphi.javaeye.com/blog/35391</link>
        <guid>http://sorphi.javaeye.com/blog/35391</guid>
      </item>
  </channel>
</rss>