﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-经验不在于年限，在于积累---专注互联网软件开发-随笔分类-HTML+CSS</title><link>http://www.blogjava.net/hankchen/category/43391.html</link><description>把工作当事业做，把项目当作品做！</description><language>zh-cn</language><lastBuildDate>Wed, 28 Mar 2012 21:11:41 GMT</lastBuildDate><pubDate>Wed, 28 Mar 2012 21:11:41 GMT</pubDate><ttl>60</ttl><item><title>session详解 zz</title><link>http://www.blogjava.net/hankchen/archive/2012/03/28/372934.html</link><dc:creator>hankchen</dc:creator><author>hankchen</author><pubDate>Wed, 28 Mar 2012 13:12:00 GMT</pubDate><guid>http://www.blogjava.net/hankchen/archive/2012/03/28/372934.html</guid><wfw:comment>http://www.blogjava.net/hankchen/comments/372934.html</wfw:comment><comments>http://www.blogjava.net/hankchen/archive/2012/03/28/372934.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hankchen/comments/commentRss/372934.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hankchen/services/trackbacks/372934.html</trackback:ping><description><![CDATA[<div><div id="msgcns!38BC563D902DC3A1!125"> 				<div> 						&nbsp;&nbsp;&nbsp; <span style="color: red;">本来打算自己写篇有关Cookie和Session的总结文章，偶然发现了这篇文章。真是写得太好了，直接转载过来，向原作者致敬！可惜找不到原文地址了。</span><br /><br /><strong>一、术语session<br /><br />　</strong>在我的经验里，session这个词被滥用的程度大概仅次于transaction，更加有趣的是transaction与session在某些语境下的含义是相同的。  <p>&nbsp;&nbsp;&nbsp;  session，中文经常翻译为会话，其本来的含义是指有始有终的一系列动作/消息，比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为 一个  session.有时候我们可以看到这样的话&#8220;在一个浏览器会话期间，&#8230;&#8230;&#8221;，这里的会话一词用的就是其本义，是指从一个浏览器窗口打开到关闭这个期间  &#9312;。最混乱的是&#8220;用户（客户端）在一次会话期间&#8221;这样一句话，它可能指用户的一系列动作（一般情况下是同某个具体目的相关的一系列动作，比如从登录到选购 商品到结账登出这样一个网上购物的过程，有时候也被称为一个transaction），然而有时候也可能仅仅是指一次连接，也有可能是指含义&#9312;，其中的差 别只能靠上下文来推断&#9313;。</p><p>&nbsp;&nbsp;&nbsp;  然而当session一词与网络协议相关联时，它又往往隐含了&#8220;面向连接&#8221;和/或&#8220;保持状态&#8221;这样两个含义，  &#8220;面向连接&#8221;指的是在通信双方在通信之前要先建立一个通信的渠道，比如打电话，直到对方接了电话通信才能开始，与此相对的是写信，在你把信发出去的时候你 并不能确认对方的地址是否正确，通信渠道不一定能建立，但对发信人来说，通信已经开始了。&#8220;保持状态&#8221;则是指通信的一方能够把一系列的消息关联起来，使得 消息之间可以互相依赖，比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有&#8220;一个TCP session&#8221;或者  &#8220;一个POP3 session&#8221;&#9314;。</p><p>&nbsp;&nbsp;&nbsp;  而到了web服务器蓬勃发展的时代，session在web开发语境下的语义又有了新的扩展，它的含义是指一类用来在客户端与服务器之间保持状态的解决方 案&#9315;。有时候session也用来指这种解决方案的存储结构，如&#8220;把xxx保存在session  里&#8221;&#9316;。由于各种用于web开发的语言在一定程度上都提供了对这种解决方案的支持，所以在某种特定语言的语境下，session也被用来指代该语言的解决 方案，比如经常把Java里提供的javax.servlet.http.HttpSession简称为session&#9317;。</p><p>&nbsp;&nbsp;&nbsp; 鉴于这种混乱已不可改变，本文中session一词的运用也会根据上下文有不同的含义，请大家注意分辨。</p><p>&nbsp;&nbsp;&nbsp; 在本文中，使用中文&#8220;浏览器会话期间&#8221;来表达含义&#9312;，使用&#8220;session机制&#8221;来表达含义&#9315;，使用&#8220;session&#8221;表达含义&#9316;，使用具体的&#8220;HttpSession&#8221;来表达含义&#9317;</p><p>&nbsp;&nbsp;&nbsp; <strong>二、HTTP协议与状态<br /><br />　</strong>保 持HTTP  协议本身是无状态的，这与HTTP协议本来的目的是相符的，客户端只需要简单的向服务器请求下载某些文件，无论是客户端还是服务器都没有必要纪录彼此过去 的行为，每一次请求之间都是独立的，好比一个顾客和一个自动售货机或者一个普通的（非会员制）大卖场之间的关系一样。</p><p>&nbsp;&nbsp;&nbsp;  然而聪明（或者贪心？）的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用，就像给有线电视加上点播功能一样。这种需求一方面迫使 HTML逐步添加了表单、脚本、DOM等客户端行为，另一方面在服务器端则出现了CGI规范以响应客户端的动态请求，作为传输载体的HTTP协议也添加了 文件上载、  cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端 与服务器之间保持状态的解决方案。</p><p>&nbsp;&nbsp;&nbsp;  让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠，然而一次性 消费5杯咖啡的机会微乎其微，这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案：1、该店的店员很厉害，能记住每位顾客 的消费数量，只要顾客一走进咖啡店，店员就知道该怎么对待了。这种做法就是协议本身支持状态。</p><p>&nbsp;&nbsp;&nbsp; 2、发给顾客一张卡片，上面记录着消费的数量，一般还有个有效期限。每次消费时，如果顾客出示这张卡片，则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。</p><p>&nbsp;&nbsp;&nbsp; 3、发给顾客一张会员卡，除了卡号之外什么信息也不纪录，每次消费时，如果顾客出示该卡片，则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。</p><p>&nbsp;&nbsp;&nbsp;   由于HTTP协议是无状态的，而出于种种考虑也不希望使之成为有状态的，因此，后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端 保持状态的方案，而session机制采用的是在服务器端保持状态的方案。同时我们也看到，由于采用服务器端保持状态的方案在客户端也需要保存一个标识， 所以session机制可能需要借助于cookie机制来达到保存标识的目的，但实际上它还有其他选择。</p><p>&nbsp;&nbsp;&nbsp; <strong>三、理解cookie机制<br /><br />　</strong>cookie机制的基本原理就如上面的例子一样简单，但是还有几个问题需要解决：&#8220;会员卡&#8221;如何分发：&#8220;会员卡&#8221;的内容；以及客户如何使用&#8220;会员卡&#8221;。</p><p>&nbsp;&nbsp;&nbsp; 正统的cookie分发是通过扩展HTTP协议来实现的，服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie.然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie.</p><p>&nbsp;&nbsp;&nbsp;  而cookie  的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie，如果某个cookie所声明的作用范围大于等于将要请求的 资源所在的位置，则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示，如果某家分店还发行了自 己的会员卡，那么进这家店的时候除了要出示麦当劳的会员卡，还要出示这家店的会员卡。</p><p>&nbsp;&nbsp;&nbsp; cookie的内容主要包括：名字，值，过期时间，路径和域。</p><p>&nbsp;&nbsp;&nbsp; 其中域可以指定某一个域比如。google.com，相当于总店招牌，比如宝洁公司，也可以指定一个域下的具体某台机器比如<a href="http://www.google.com/"><u>www.google.com</u></a>或者froogle.google.com，可以用飘柔来做比。</p><p>&nbsp;&nbsp;&nbsp; 路径就是跟在域名后面的URL路径，比如/或者/foo等等，可以用某飘柔专柜做比。</p><p>&nbsp;&nbsp;&nbsp; 路径与域合在一起就构成了cookie的作用范围。</p><p>&nbsp;&nbsp;&nbsp;  如果不设置过期时间，则表示这个cookie的生命期为浏览器会话期间，只要关闭浏览器窗口，cookie就消失了。这种生命期为浏览器会话期的  cookie被称为会话cookie.会话cookie一般不存储在硬盘上而是保存在内存里，当然这种行为并不是规范规定的。如果设置了过期时间，浏览器 就会把cookie保存到硬盘上，关闭后再次打开浏览器，这些cookie仍然有效直到超过设定的过期时间。</p><p>&nbsp;&nbsp;&nbsp;  存储在硬盘上的cookie  可以在不同的浏览器进程间共享，比如两个IE窗口。而对于保存在内存里的cookie，不同的浏览器有不同的处理方式。对于IE，在一个打开的窗口上按  Ctrl-N（或者从文件菜单）打开的窗口可以与原窗口共享，而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie；对于  Mozilla  Firefox0.8，所有的进程和标签页都可以共享同样的cookie.一般来说是用javascript的window.open打开的窗口会与原窗 口共享内存cookie.浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很 大的困扰。</p><p>&nbsp;&nbsp;&nbsp; 下面就是一个goolge设置cookie的响应头的例子HTTP/1.1 302 FoundLocation： <a href="http://www.google.com/intl/zh-CN/Set-Cookie"><u>http://www.google.com/intl/zh-CN/Set-Cookie</u></a>：   PREF=ID=0565f77e132de138：NW=1：TM=1098082649：LM=1098082649：S=KaeaCFPo49RiA_d8；  expires=Sun， 17-Jan-2038 19：14：07 GMT； path=/；  domain=.google.comContent-Type： text/html</p><p align="center"><img style="display: inline" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125320274.jpg" border="0" /></p><p>&nbsp;&nbsp;&nbsp; 这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分</p><p align="center"><img style="display: inline" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125320533.jpg" border="0" /></p><p>&nbsp;&nbsp;&nbsp; 浏览器在再次访问goolge的资源时自动向外发送cookie</p><p align="center"><img style="display: inline" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125322468.jpg" border="0" /></p><p>&nbsp;&nbsp;&nbsp; 用Firefox可以很容易的观察现有的cookie的值使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。</p><p align="center"><img style="display: inline" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125322207.jpg" border="0" /></p><p>&nbsp;&nbsp;&nbsp; IE也可以设置在接受cookie前询问</p><p>&nbsp;&nbsp;&nbsp;<strong> 四、理解session机制</strong></p><p>&nbsp;&nbsp;&nbsp; session机制是一种服务器端的机制，服务器使用一种类似于散列表的结构（也可能就是使用散列表）来保存信息。</p><p>&nbsp;&nbsp;&nbsp;  当程序需要为某个客户端的请求创建一个session的时候，服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为  session id，如果已包含一个session id则说明以前已经为此客户端创建过session，服务器就按照session id把这个  session检索出来使用（如果检索不到，可能会新建一个），如果客户端请求不包含session  id，则为此客户端创建一个session并且生成一个与此session相关联的session id，session  id的值应该是一个既不会重复，又不容易被找到规律以仿造的字符串，这个 session id将被在本次响应中返回给客户端保存。</p><p>&nbsp;&nbsp;&nbsp;  保存这个session  id的方式可以采用cookie，这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于 SEEESIONID，而。比如weblogic对于web应用程序生成的cookie，JSESSIONID=  ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng！-145788764，它的名字就是  JSESSIONID.</p><p>&nbsp;&nbsp;&nbsp; 由于cookie可以被人为的禁止，必须有其他机制以便在cookie被禁止时仍然能够把session  id传递回服务器。经常被使用的一种技术叫做URL重写，就是把session  id直接附加在URL路径的后面，附加方式也有两种，一种是作为URL路径的附加信息，表现形式为<a href="http://%e2%80%a6%e2%80%a6/xxx"><u>http://&#8230;&#8230;/xxx</u></a>；jsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng！-145788764另一种是作为查询字符串附加在URL后面，表现形式为<a href="http://%e2%80%a6%e2%80%a6/xxx"><u>http://&#8230;&#8230;/xxx</u></a>？jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng！-145788764 这两种方式对于用户来说是没有区别的，只是服务器在解析的时候处理的方式不同，采用第一种方式也有利于把session  id的信息和正常程序参数区分开来。</p><p>&nbsp;&nbsp;&nbsp; 为了在整个交互过程中始终保持状态，就必须在每个客户端可能请求的路径后面都包含这个session id.</p><p>&nbsp;&nbsp;&nbsp;  另一种技术叫做表单隐藏字段。就是服务器会自动修改表单，添加一个隐藏字段，以便在表单提交时能够把session  id传递回服务器。比如下面的表单&lt;form name="testform" action="/xxx"&gt;&lt;input  type="text"&gt;&lt;/form&gt;</p><p>&nbsp;&nbsp;&nbsp; 在被传递给客户端之前将被改写成&lt;form  name="testform" action="/xxx"&gt;&lt;input type="hidden"  name="jsessionid"  value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng！-145788764"&amp; gt;&lt;input type="text"&gt;&lt;/form&gt;</p><p>&nbsp;&nbsp;&nbsp; 这种技术现在已较少应用，笔者接触过的很古老的iPlanet6（SunONE应用服务器的前身）就使用了这种技术。</p><p>&nbsp;&nbsp;&nbsp; 实际上这种技术可以简单的用对action应用URL重写来代替。</p><p>&nbsp;&nbsp;&nbsp;   在谈论session机制的时候，常常听到这样一种误解&#8220;只要关闭浏览器，session就消失了&#8221;。其实可以想象一下会员卡的例子，除非顾客主动对店家 提出销卡，否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的，除非程序通知服务器删除一个session，否则服务器会一直保留，程 序一般都是在用户做log  off的时候发个指令去删除session.然而浏览器从来不会主动在关闭之前通知服务器它将要关闭，因此服务器根本不会有机会知道浏览器已经关闭，之所 以会有这种错觉，是大部分session机制都使用会话cookie来保存session id，而关闭浏览器后这个 session  id就消失了，再次连接服务器时也就无法找到原来的session.如果服务器设置的cookie被保存到硬盘上，或者使用某种手段改写浏览器发出的 HTTP请求头，把原来的session id发送给服务器，则再次打开浏览器仍然能够找到原来的session.</p><p>&nbsp;&nbsp;&nbsp; 恰恰是由于关闭浏览器不会导致session被删除，迫使服务器为seesion设置了一个失效时间，当距离客户端上一次使用session的时间超过这个失效时间时，服务器就可以认为客户端已经停止了活动，才会把session删除以节省存储空间。</p><p>&nbsp;&nbsp;&nbsp; <strong>五、理解javax.servlet.http.HttpSession<br /><br />　</strong> HttpSession是Java平台对session机制的实现规范，因为它仅仅是个接口，具体到每个web应用服务器的提供商，除了对规范支持之外，仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作为例子来演示。</p><p>&nbsp;&nbsp;&nbsp;  首先，Weblogic  Server提供了一系列的参数来控制它的HttpSession的实现，包括使用cookie的开关选项，使用URL重写的开关选项，session持 久化的设置，session失效时间的设置，以及针对cookie的各种设置，比如设置cookie的名字、路径、域， cookie的生存时间等。</p><p>&nbsp;&nbsp;&nbsp;   一般情况下，session都是存储在内存里，当服务器进程被停止或者重启的时候，内存里的session也会被清空，如果设置了session的持久化 特性，服务器就会把session保存到硬盘上，当服务器进程重新启动或这些信息将能够被再次使用， Weblogic  Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。</p><p>&nbsp;&nbsp;&nbsp; 复制严格说来不算持久化保存，因为session实际上还是保存在内存里，不过同样的信息被复制到各个cluster内的服务器进程中，这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session.</p><p>&nbsp;&nbsp;&nbsp; cookie生存时间的设置则会影响浏览器生成的cookie是否是一个会话cookie.默认是使用会话cookie.有兴趣的可以用它来试验我们在第四节里提到的那个误解。</p><p>&nbsp;&nbsp;&nbsp; cookie的路径对于web应用程序来说是一个非常重要的选项，Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。</p><p>&nbsp;&nbsp;&nbsp; 关于session的设置参考[5] <a href="http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869"><u>http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869</u></a></p><p>&nbsp;&nbsp;&nbsp;<strong> 六、HttpSession常见问题</strong>（在本小节中session的含义为&#9316;和&#9317;的混合）</p><p>&nbsp;&nbsp;&nbsp;  1、session在何时被创建一个常见的误解是以为session在有客户端访问时就被创建，然而事实是直到某server端程序调用  HttpServletRequest.getSession（true）这样的语句时才被创建，注意如果JSP没有显示的使用 &lt;% @page  session="false"%&gt; 关闭session，则JSP文件在编译成Servlet时将会自动加上这样一条语句  HttpSession session = HttpServletRequest.getSession（true）；这也是JSP中隐含的  session对象的来历。</p><p>&nbsp;&nbsp;&nbsp; 由于session会消耗内存资源，因此，如果不打算使用session，应该在所有的JSP中关闭它。</p><p>&nbsp;&nbsp;&nbsp;   2、session何时被删除综合前面的讨论，session在下列情况下被删除a.程序调用HttpSession.invalidate（）；或b. 距离上一次收到客户端发送的session id时间间隔超过了session的超时设置；或c.服务器进程被停止（非持久session）</p><p>&nbsp;&nbsp;&nbsp;   3、如何做到在浏览器关闭时删除session严格的讲，做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码 window.oncolose来监视浏览器的关闭动作，然后向服务器发送一个请求来删除session.但是对于浏览器崩溃或者强行杀死进程这些非常规 手段仍然无能为力。</p><p>&nbsp;&nbsp;&nbsp;  4、有个HttpSessionListener是怎么回事你可以创建这样的listener去监控session的创建和销毁事件，使得在发生这样的事 件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener，而不是相反。类似的与HttpSession有关的 listener还有 HttpSessionBindingListener，HttpSessionActivationListener和  HttpSessionAttributeListener.</p><p>&nbsp;&nbsp;&nbsp;  5、存放在session中的对象必须是可序列化的吗不是必需的。要求对象可序列化只是为了session能够在集群中被复制或者能够持久保存或者在必要 时server能够暂时把session交换出内存。在 Weblogic  Server的session中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果  session中有不可序列化的对象，在session销毁时会有一个Exception，很奇怪。</p><p>&nbsp;&nbsp;&nbsp; 6、如何才能正确的应付客户端禁止cookie的可能性对所有的URL使用URL重写，包括超链接，form的action，和重定向的URL，具体做法参见[6] <a href="http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770"><u>http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770</u></a></p><p>&nbsp;&nbsp;&nbsp; 7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session参见第三小节对cookie的讨论，对session来说是只认id不认人，因此不同的浏览器，不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。</p><p>&nbsp;&nbsp;&nbsp;   8、如何防止用户打开两个浏览器窗口操作导致的session混乱这个问题与防止表单多次提交是类似的，可以通过设置客户端的令牌来解决。就是在服务器每 次生成一个不同的id返回给客户端，同时保存在session里，客户端提交表单时必须把这个id也返回服务器，程序首先比较返回的id与保存在 session里的值是否一致，如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用 javascript  window.open打开的窗口，一般不设置这个id，或者使用单独的id，以防主窗口无法操作，建议不要再window.open打开的窗口里做修改 操作，这样就可以不用设置。</p><p>&nbsp;&nbsp;&nbsp; 9、为什么在Weblogic  Server中改变session的值后要重新调用一次session.setValue做这个动作主要是为了在集群环境中提示Weblogic  Server session中的值发生了改变，需要向其他服务器进程复制新的session值。</p><p>&nbsp;&nbsp;&nbsp;  10、为什么session不见了排除session正常失效的因素之外，服务器本身的可能性应该是微乎其微的，虽然笔者在iPlanet6SP1加若干 补丁的Solaris版本上倒也遇到过；浏览器插件的可能性次之，笔者也遇到过3721插件造成的问题；理论上防火墙或者代理服务器在cookie处理上 也有可能会出现问题。</p><p>&nbsp;&nbsp;&nbsp; 出现这一问题的大部分原因都是程序的错误，最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨论这个问题。</p><p>&nbsp;<strong>&nbsp;&nbsp; 七、跨应用程序的session共享</strong></p><p>&nbsp;&nbsp;&nbsp;   常常有这样的情况，一个大项目被分割成若干小项目开发，为了能够互不干扰，要求每个小项目作为一个单独的web应用程序开发，可是到了最后突然发现某几个 小项目之间需要共享一些信息，或者想使用session来实现SSO（single sign  on），在session中保存login的用户信息，最自然的要求是应用程序间能够访问彼此的session.</p><p>&nbsp;&nbsp;&nbsp;  然而按照Servlet规范，session的作用范围应该仅仅限于当前应用程序下，不同的应用程序之间是不能够互相访问对方的session的。各个应 用服务器从实际效果上都遵守了这一规范，但是实现的细节却可能各有不同，因此解决跨应用程序session共享的方法也各不相同。</p><p>&nbsp;&nbsp;&nbsp;  首先来看一下Tomcat是如何实现web应用程序之间session的隔离的，从  Tomcat设置的cookie路径来看，它对不同的应用程序设置的cookie路径是不同的，这样不同的应用程序所用的session  id是不同的，因此即使在同一个浏览器窗口里访问不同的应用程序，发送给服务器的session id也可以是不同的。</p><p align="center"><img style="display: inline" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125323841.jpg" border="0" /></p><p align="center"><img style="display: inline" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125323233.jpg" border="0" /></p><p>&nbsp;&nbsp;&nbsp; 根据这个特性，我们可以推测Tomcat中session的内存结构大致如下。</p><p align="center"><img style="display: inline" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125323802.jpg" border="0" /></p><p>&nbsp;&nbsp;&nbsp;   笔者以前用过的iPlanet也采用的是同样的方式，估计SunONE与iPlanet之间不会有太大的差别。对于这种方式的服务器，解决的思路很简单， 实际实行起来也不难。要么让所有的应用程序共享一个session id，要么让应用程序能够获得其他应用程序的session id.</p><p>&nbsp;&nbsp;&nbsp; iPlanet中有一种很简单的方法来实现共享一个session id，那就是把各个应用程序的cookie路径都设为/（实际上应该是/NASApp，对于应用程序来讲它的作用相当于根）。</p><p>&nbsp;&nbsp;&nbsp; &lt;session-info&gt;&lt;path&gt;/NASApp&lt;/path&gt;&lt;/session-info&gt;</p><p>&nbsp;&nbsp;&nbsp;  需要注意的是，操作共享的session应该遵循一些编程约定，比如在session attribute名字的前面加上应用程序的前缀，使得  setAttribute（"name"， "neo"）变成setAttribute（"app1.name"，  "neo"），以防止命名空间冲突，导致互相覆盖。</p><p>&nbsp;&nbsp;&nbsp;  在Tomcat中则没有这么方便的选择。在Tomcat版本3上，我们还可以有一些手段来共享session.对于版本4以上的Tomcat，目前笔者尚 未发现简单的办法。只能借助于第三方的力量，比如使用文件、数据库、JMS或者客户端cookie，URL参数或者隐藏字段等手段。</p><p>&nbsp;&nbsp;&nbsp; 我们再看一下Weblogic Server是如何处理session的。</p><p align="center"><img style="display: inline" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125323420.jpg" border="0" /></p><p align="center"><img style="display: inline" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125324813.jpg" border="0" /></p><p>&nbsp;&nbsp;&nbsp;  从截屏画面上可以看到Weblogic Server对所有的应用程序设置的cookie的路径都是/，这是不是意味着在Weblogic  Server中默认的就可以共享session了呢？然而一个小实验即可证明即使不同的应用程序使用的是同一个session，各个应用程序仍然只能访问 自己所设置的那些属性。这说明Weblogic Server中的session的内存结构可能如下</p><p align="center"><img style="display: inline" alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200603/20060314125324805.jpg" border="0" /></p><p>&nbsp;&nbsp;&nbsp;  对于这样一种结构，在  session机制本身上来解决session共享的问题应该是不可能的了。除了借助于第三方的力量，比如使用文件、数据库、JMS或者客户端  cookie，URL参数或者隐藏字段等手段，还有一种较为方便的做法，就是把一个应用程序的session放到ServletContext中，这样另 外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下，</p><p>&nbsp;&nbsp;&nbsp; 应用程序A context.setAttribute（"appA"， session）；</p><p>&nbsp;&nbsp;&nbsp; 应用程序B contextA = context.getContext（"/appA"）；HttpSession sessionA = （HttpSession）contextA.getAttribute（"appA"）；</p><p>&nbsp;&nbsp;&nbsp; 值得注意的是这种用法不可移植，因为根据ServletContext的JavaDoc，应用服务器可以处于安全的原因对于context.getContext（"/appA"）；返回空值，以上做法在Weblogic Server 8.1中通过。</p><p>&nbsp;&nbsp;&nbsp;  那么Weblogic  Server为什么要把所有的应用程序的cookie路径都设为/呢？原来是为了SSO，凡是共享这个session的应用程序都可以共享认证的信息。一 个简单的实验就可以证明这一点，修改首先登录的那个应用程序的描述符weblogic.xml，把cookie路径修改为/appA  访问另外一个应用程序会重新要求登录，即使是反过来，先访问cookie路径为/的应用程序，再访问修改过路径的这个，虽然不再提示登录，但是登录的用户 信息也会丢失。注意做这个实验时认证方式应该使用FORM，因为浏览器和web服务器对basic认证方式有其他的处理方式，第二次请求的认证不是通过  session来实现的。具体请参看[7] secion 14.8 Authorization，你可以修改所附的示例程序来做这些试验。</p><p>&nbsp;&nbsp;&nbsp; <strong>八、总结<br /><br />　</strong>session机制本身并不复杂，然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器，服务器的经验当作普遍适用的经验，而是始终需要具体情况具体分析。</p><p>&nbsp;&nbsp;&nbsp;   摘要：虽然session机制在web应用程序中被采用已经很长时间了，但是仍然有很多人不清楚session机制的本质，以至不能正确的应用这一技术。 本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。</p></div> 		</div></div><img src ="http://www.blogjava.net/hankchen/aggbug/372934.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hankchen/" target="_blank">hankchen</a> 2012-03-28 21:12 <a href="http://www.blogjava.net/hankchen/archive/2012/03/28/372934.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CSS布局常用的方法：float:none|left|right （转载）</title><link>http://www.blogjava.net/hankchen/archive/2010/02/27/314056.html</link><dc:creator>hankchen</dc:creator><author>hankchen</author><pubDate>Sat, 27 Feb 2010 05:01:00 GMT</pubDate><guid>http://www.blogjava.net/hankchen/archive/2010/02/27/314056.html</guid><wfw:comment>http://www.blogjava.net/hankchen/comments/314056.html</wfw:comment><comments>http://www.blogjava.net/hankchen/archive/2010/02/27/314056.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hankchen/comments/commentRss/314056.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hankchen/services/trackbacks/314056.html</trackback:ping><description><![CDATA[<div class="cnt"><span class="un1421"><font size="3"><strong><span class="hilite1">CSS</span>布局常用的方法：<span class="hilite2">float</span>:none|<span class="hilite3">left</span>|<span class="hilite4">right</span>&nbsp;<br />
</strong>取值：<br />
none:&nbsp;默认值。对象不飘浮<br />
<span class="hilite3">left</span>:&nbsp;文本流向对象的右边<br />
<span class="hilite4">right</span>:&nbsp;文本流向对象的左边&nbsp;<br />
<br />
它是怎样工作的，看个一行两列的例子&nbsp;<br />
xhtml:<br />
&lt;div&nbsp;id="wrap"&gt;<br />
&lt;div&nbsp;id="column1"&gt;这里是第一列&lt;/div&gt;<br />
&lt;div&nbsp;id="column2"&gt;这里是第二列&lt;/div&gt;<br />
&lt;div&nbsp;class="clear"&gt;&lt;/div&gt;&nbsp;/*这是违背web标准意图的，只是想说明在它下面的元素需要清除浮动*/<br />
&lt;/div&gt;&nbsp;<br />
<span class="hilite1">CSS</span>:<br />
#wrap{width:100;height:auto;}<br />
#column1{<span class="hilite2">float</span>:<span class="hilite3">left</span>;width:40;}<br />
#column2{<span class="hilite2">float</span>:<span class="hilite4">right</span>;width:60;}<br />
.clear{clear:both;}<br />
<br />
<strong>position:static|absolute|fixed|relative</strong><br />
取值：<br />
static:&nbsp;默认值。无特殊定位，对象遵循HTML定位规则<br />
absolute:&nbsp;将对象从文档流中拖出，使用<span class="hilite3">left</span>，<span class="hilite4">right</span>，top，bottom等属性相对于其最接近的一个最有定位设置的父对象进行绝对定位。如果不存在这样的父对象，则依据body对象。而其层叠通过z-index属性定义<br />
fixed:&nbsp;未支持。对象定位遵从绝对(absolute)方式。但是要遵守一些规范<br />
relative:&nbsp;对象不可层叠，但将依据<span class="hilite3">left</span>，<span class="hilite4">right</span>，top，bottom等属性在正常文档流中偏移位置&nbsp;<br />
<br />
它来实现一行两列的例子&nbsp;<br />
xhtml:<br />
&lt;div&nbsp;id="wrap"&gt;<br />
&lt;div&nbsp;id="column1"&gt;这里是第一列&lt;/div&gt;<br />
&lt;div&nbsp;id="column2"&gt;这里是第二列&lt;/div&gt;<br />
&lt;/div&gt;&nbsp;<br />
<span class="hilite1">CSS</span>:<br />
#wrap{position:relative;/*相对定位*/width:770px;}<br />
#column1{position:absolute;top:0;<span class="hilite3">left</span>:0;width:300px;}<br />
#column2{position:absolute;top:0;<span class="hilite4">right</span>:0;width:470px;}&nbsp;<br />
他们的区别在哪?&nbsp;<br />
显然，<span class="hilite2">float</span>是相对定位的，会随着浏览器的大小和分辨率的变化而改变，而position就不行了，所以一般情况下还是<span class="hilite2">float</span>布局！<br />
<br />
<strong><span class="hilite1">CSS</span>常用布局实例</strong><br />
<br />
<strong>单行一列</strong><br />
body{margin:0px;padding:0px;text-align:center;}<br />
#content{margin-<span class="hilite3">left</span>:auto;margin-<span class="hilite4">right</span>:auto;width:400px;}&nbsp;<br />
<br />
<strong>两行一列</strong>&nbsp;<br />
body{margin:0px;padding:0px;text-align:center;}<br />
#content-top{margin-<span class="hilite3">left</span>:auto;margin-<span class="hilite4">right</span>:auto;width:400px;}<br />
#content-end{margin-<span class="hilite3">left</span>:auto;margin-<span class="hilite4">right</span>:auto;width:400px;}&nbsp;<br />
<br />
<strong>三行一列</strong>&nbsp;<br />
body{margin:0px;padding:0px;text-align:center;}<br />
#content-top{margin-<span class="hilite3">left</span>:auto;margin-<span class="hilite4">right</span>:auto;width:400px;width:370px;}<br />
#content-mid{margin-<span class="hilite3">left</span>:auto;margin-<span class="hilite4">right</span>:auto;width:400px;}<br />
#content-end{margin-<span class="hilite3">left</span>:auto;margin-<span class="hilite4">right</span>:auto;width:400px;}<br />
<br />
<strong>单行两列</strong>&nbsp;<br />
#bodycenter{width:700px;margin-<span class="hilite4">right</span>:auto;margin-<span class="hilite3">left</span>:auto;overflow:auto;}<br />
#bodycenter#dv1{<span class="hilite2">float</span>:<span class="hilite3">left</span>;width:280px;}<br />
#bodycenter#dv2{<span class="hilite2">float</span>:<span class="hilite4">right</span>;width:420px;}&nbsp;<br />
<br />
<strong>两行两列</strong><br />
#header{width:700px;margin-<span class="hilite4">right</span>:auto;margin-<span class="hilite3">left</span>:auto;overflow:auto;}<br />
#bodycenter{width:700px;margin-<span class="hilite4">right</span>:auto;margin-<span class="hilite3">left</span>:auto;overflow:auto;}<br />
#bodycenter#dv1{<span class="hilite2">float</span>:<span class="hilite3">left</span>;width:280px;}<br />
#bodycenter#dv2{<span class="hilite2">float</span>:<span class="hilite4">right</span>;width:420px;}&nbsp;<br />
<br />
<strong>三行两列</strong><br />
#header{width:700px;margin-<span class="hilite4">right</span>:auto;margin-<span class="hilite3">left</span>:auto;}<br />
#bodycenter{width:700px;margin-<span class="hilite4">right</span>:auto;margin-<span class="hilite3">left</span>:auto;}<br />
#bodycenter#dv1{<span class="hilite2">float</span>:<span class="hilite3">left</span>;width:280px;}<br />
#bodycenter#dv2{<span class="hilite2">float</span>:<span class="hilite4">right</span>;width:420px;}<br />
#footer{width:700px;margin-<span class="hilite4">right</span>:auto;margin-<span class="hilite3">left</span>:auto;overflow:auto;clear:both;}&nbsp;<br />
<br />
<strong>单行三列</strong><br />
<br />
<strong>绝对定位</strong>&nbsp;<br />
#<span class="hilite3">left</span>{position:absolute;top:0px;<span class="hilite3">left</span>:0px;width:120px;}<br />
#middle{margin:0px190px0px190px;}<br />
#<span class="hilite4">right</span>{position:absolute;top:0px;<span class="hilite4">right</span>:0px;width:120px;}&nbsp;<br />
<br />
<strong><span class="hilite2">float</span>定位</strong><br />
xhtml:<br />
&lt;div&nbsp;id="wrap"&gt;<br />
&lt;div&nbsp;id="column"&gt;<br />
&lt;div&nbsp;id="column1"&gt;这里是第一列&lt;/div&gt;<br />
&lt;div&nbsp;id="column2"&gt;这里是第二列&lt;/div&gt;<br />
<span style="color: red">&lt;div&nbsp;class="clear"&gt;&lt;/div&gt;/*用法web标准不建议，但是记住下面元素需要清除浮动*/</span><br />
&lt;/div&gt;<br />
&lt;divid="column3"&gt;这里是第三列&lt;/div&gt;<br />
&lt;divclass="clear"&gt;&lt;/div&gt;/*用法web标准不建议，但是记住下面元素需要清除浮动*/<br />
&lt;/div&gt;&nbsp;<br />
<span class="hilite1">CSS</span>:<br />
#wrap{width:100;height:auto;}<br />
#column{<span class="hilite2">float</span>:<span class="hilite3">left</span>;width:60;}<br />
#column1{<span class="hilite2">float</span>:<span class="hilite3">left</span>;width:30;}<br />
#column2{<span class="hilite2">float</span>:<span class="hilite4">right</span>;width:30;}<br />
#column3{<span class="hilite2">float</span>:<span class="hilite4">right</span>;width:40;}<br />
.clear{clear:both;}&nbsp;<br />
<br />
<strong><span class="hilite2">float</span>定位二</strong><br />
xhtml<br />
&lt;div&nbsp;id="center"class="column"&gt;<br />
&lt;h1&gt;Thisisthemaincontent.&lt;/h1&gt;<br />
&lt;/div&gt;<br />
&lt;div&nbsp;id="<span class="hilite3">left</span>"class="column"&gt;<br />
&lt;h2&gt;Thisistheleftsidebar.&lt;/h2&gt;<br />
&lt;/div&gt;<br />
&lt;div&nbsp;id="<span class="hilite4">right</span>"class="column"&gt;<br />
&lt;h2&gt;Thisistherightsidebar.&lt;/h2&gt;<br />
&lt;/div&gt;<br />
<span class="hilite1">CSS</span><br />
body{<br />
margin:0;<br />
padding-<span class="hilite3">left</span>:200px;/*LCfullwidth*/<br />
padding-<span class="hilite4">right</span>:190px;/*RCfullwidth&nbsp;CCpadding*/<br />
min-width:200px;/*LCfullwidth&nbsp;CCpadding*/<br />
}<br />
.column{<br />
position:relative;<br />
<span class="hilite2">float</span>:<span class="hilite3">left</span>;<br />
}<br />
#center{<br />
width:100;<br />
}<br />
#<span class="hilite3">left</span>{<br />
width:200px;/*LCwidth*/<br />
<span class="hilite4">right</span>:200px;/*LCfullwidth*/<br />
margin-<span class="hilite3">left</span>:-100;<br />
}<br />
#<span class="hilite4">right</span>{<br />
width:190px;/*RCwidth*/<br />
margin-<span class="hilite4">right</span>:-100;<br />
}<br />
<br />
/***IEFix***/<br />
*html#<span class="hilite3">left</span>{<br />
<span class="hilite3">left</span>:190px;/*RCfullwidth*/<br />
}<br />
<br />
<strong>两行三列</strong>&nbsp;<br />
xhtml:<br />
<br />
&lt;div&nbsp;id="header"&gt;这里是顶行&lt;/div&gt;<br />
&lt;div&nbsp;id="warp"&gt;<br />
&lt;div&nbsp;id="column"&gt;<br />
&lt;div&nbsp;id="column1"&gt;这里是第一列&lt;/div&gt;<br />
&lt;div&nbsp;id="column2"&gt;这里是第二列&lt;/div&gt;<br />
&lt;div&nbsp;class="clear"&gt;&lt;/div&gt;<br />
&lt;/div&gt;<br />
&lt;div&nbsp;id="column3"&gt;这里是第三列&lt;/div&gt;<br />
&lt;div&nbsp;class="clear"&gt;&lt;/div&gt;<br />
&lt;/div&gt;&nbsp;<br />
<span class="hilite1">CSS</span>:<br />
#header{width:100;height:auto;}<br />
#wrap{width:100;height:auto;}<br />
#column{<span class="hilite2">float</span>:<span class="hilite3">left</span>;width:60;}<br />
#column1{<span class="hilite2">float</span>:<span class="hilite3">left</span>;width:30;}<br />
#column2{<span class="hilite2">float</span>:<span class="hilite4">right</span>;width:30;}<br />
#column3{<span class="hilite2">float</span>:<span class="hilite4">right</span>;width:40;}<br />
.clear{clear:both;}&nbsp;<br />
<br />
<strong>三行三列&nbsp;</strong><br />
xhtml:<br />
&lt;div&nbsp;id="header"&gt;这里是顶行&lt;/div&gt;<br />
&lt;div&nbsp;id="wrap"&gt;<br />
&lt;div&nbsp;id="column"&gt;<br />
&lt;div&nbsp;id="column1"&gt;这里是第一列&lt;/div&gt;<br />
&lt;div&nbsp;id="column2"&gt;这里是第二列&lt;/div&gt;<br />
&lt;div&nbsp;class="clear"&gt;&lt;/div&gt;<br />
&lt;/div&gt;<br />
&lt;div&nbsp;id="column3"&gt;这里是第三列&lt;/div&gt;<br />
&lt;div&nbsp;class="clear"&gt;&lt;/div&gt;<br />
&lt;/div&gt;<br />
&lt;div&nbsp;id="footer"&gt;这里是底部一行&lt;/div&gt;<br />
<span class="hilite1">CSS</span>:<br />
#header{width:100;height:auto;}<br />
#wrap{width:100;height:auto;}<br />
#column{<span class="hilite2">float</span>:<span class="hilite3">left</span>;width:60;}<br />
#column1{<span class="hilite2">float</span>:<span class="hilite3">left</span>;width:30;}<br />
#column2{<span class="hilite2">float</span>:<span class="hilite4">right</span>;width:30;}<br />
#column3{<span class="hilite2">float</span>:<span class="hilite4">right</span>;width:40;}<br />
.clear{clear:both;}<br />
#footer{width:100;height:auto;}&nbsp;<br />
<br />
PS:这里列出的是常用的例子，而非研究之用，对一每个盒子，我都没有设置margin,padding,boeder等属性，是因为我个人觉得，含有宽度定位的时候，最好不好用到他们，除非必不得已，因为如果不是这样的话，解决浏览器兼容问题，会让你头疼，而且产生一系列<span class="hilite1">CSS</span>代码，我觉得这样的效率和效果都不好！&nbsp;<br />
<br />
<strong><span class="hilite1">CSS</span>布局高级技巧</strong><br />
margin和padding总是有可能要用到，而产生的问题如何解决呢？由于浏览器解释容器宽度的方法不同：<br />
IE6.0FirefoxOpera等是<br />
真实宽度=width&nbsp;padding&nbsp;border&nbsp;margin<br />
IE5.X<br />
真实宽度=width-padding-border-margin&nbsp;<br />
<br />
IE中有浮动对象的双倍距离之BUG（IEDoubledFloat-MarginBug）,这里还需要具体问题具体解决，下面是解决办法www.forest53.com/tutorials/tutorials_show.asp?id=31<br />
<br />
很明显，第一种下很完美的布局在第二种情况下后果是很凄惨的！&nbsp;<br />
解决的方法是hack&nbsp;<br />
div.content{<br />
width:400px;//这个是错误的width，所有浏览器都读到了<br />
voice-family:"\"}\"";//IE5.X/win忽略了"\"}\""后的内容<br />
voice-family:inherit;<br />
width:300px;//包括IE6/win在内的部分浏览器读到这句，新的数值(300px)覆盖掉了旧的<br />
}<br />
html&gt;body.content{//html&gt;body是CSS2的写法<br />
width:300px;//支持CSS2该写法的浏览器(非IE5)有幸读到了这一句<br />
}<br />
<br />
div.content{<br />
width:300px!important;//这个是正确的width，大部分支持!important标记的浏览器使用这里的数值<br />
width(空格)/**/:400px;//IE6/win不解析这句，所以IE6/win仍然认为width的值是300px；而IE5.X/win读到这句，新的数值(400px)覆盖掉了旧的，因为!important标记对他们不起作用<br />
}<br />
html&gt;body.content{//html&gt;body是CSS2的写法<br />
width:300px;//支持CSS2该写法的浏览器有幸读到了这一句<br />
}&nbsp;<br />
<br />
<strong>列等高技巧</strong><br />
n行n列布局，每列高度（事先并不能确定哪列的高度）的相同，是每个设计师追求的目标，做法有：背景图填充、加JS脚本的<br />
方法和容器溢出部分隐藏和列的负底边界和正的内补丁相结合的方法。<br />
<br />
<strong>背景图填充法：</strong><br />
xhtml:<br />
&lt;div&nbsp;id="wrap"&gt;<br />
&lt;div&nbsp;id="column1"&gt;这是第一列&lt;/div&gt;<br />
&lt;div&nbsp;id="column1"&gt;这是第二列&lt;/div&gt;<br />
&lt;div&nbsp;class="clear"&gt;&lt;/div&gt;<br />
&lt;/div&gt;<br />
<span class="hilite1">css</span>:<br />
#wrap{width:776px;background:url(bg.gif)repeat-y300px;}<br />
#column1{<span class="hilite2">float</span>:<span class="hilite3">left</span>;width:300px;}<br />
#column2{<span class="hilite2">float</span>:<span class="hilite4">right</span>;width:476px;}<br />
.clear{clear:both;}&nbsp;<br />
<br />
就是将一个npx宽的一张图片在外部容器纵向重复，定位到两列交错的位置纵向重复，在视觉上产生了两列高度一样的错觉。</font></span></div>
<img src ="http://www.blogjava.net/hankchen/aggbug/314056.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hankchen/" target="_blank">hankchen</a> 2010-02-27 13:01 <a href="http://www.blogjava.net/hankchen/archive/2010/02/27/314056.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>IE7不支持min-width？</title><link>http://www.blogjava.net/hankchen/archive/2010/02/27/314049.html</link><dc:creator>hankchen</dc:creator><author>hankchen</author><pubDate>Sat, 27 Feb 2010 02:50:00 GMT</pubDate><guid>http://www.blogjava.net/hankchen/archive/2010/02/27/314049.html</guid><wfw:comment>http://www.blogjava.net/hankchen/comments/314049.html</wfw:comment><comments>http://www.blogjava.net/hankchen/archive/2010/02/27/314049.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/hankchen/comments/commentRss/314049.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hankchen/services/trackbacks/314049.html</trackback:ping><description><![CDATA[最近做一个项目，发现有个页面设置<font style="background-color: #cce8cf">style="min-width:1000px;"</font>在IE7中无效。这个不应该啊，因为以前做的很多页面都可以的，这次为什么就不行了呢？<br />
后来发现是<font style="background-color: #cce8cf">&lt;!DOCTYPE&gt;声明惹的祸。将声明：<br />
<font style="background-color: #cce8cf">&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;</font>改为：<br />
<font style="background-color: #cce8cf">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;即可。<br />
记录下来备录。<br />
</font><br />
</font><br />
<br />
<img src ="http://www.blogjava.net/hankchen/aggbug/314049.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hankchen/" target="_blank">hankchen</a> 2010-02-27 10:50 <a href="http://www.blogjava.net/hankchen/archive/2010/02/27/314049.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>