??xml version="1.0" encoding="utf-8" standalone="yes"?>а√在线中文网新版地址在线,国产精品都在这里,国产一区福利在线http://www.aygfsteel.com/hankchen/category/43391.html把工作当事业做,把项目当作品做!zh-cnWed, 28 Mar 2012 21:11:41 GMTWed, 28 Mar 2012 21:11:41 GMT60session详解 zzhttp://www.aygfsteel.com/hankchen/archive/2012/03/28/372934.htmlhankchenhankchenWed, 28 Mar 2012 13:12:00 GMThttp://www.aygfsteel.com/hankchen/archive/2012/03/28/372934.htmlhttp://www.aygfsteel.com/hankchen/comments/372934.htmlhttp://www.aygfsteel.com/hankchen/archive/2012/03/28/372934.html#Feedback0http://www.aygfsteel.com/hankchen/comments/commentRss/372934.htmlhttp://www.aygfsteel.com/hankchen/services/trackbacks/372934.html
    本来打算自己写篇有关Cookie和Session的ȝ文章Q偶然发Cq篇文章。真是写得太好了Q直接{载过来,向原作者致敬!可惜找不到原文地址了?/span>

一、术语session

 
在我的经验里Qsessionq个词被滥用的程度大概仅ơ于transactionQ更加有的是transaction与session在某些语境下的含义是相同的?

    sessionQ中文经常翻译ؓ会话Q其本来的含义是指有始有l的一pd动作/消息Q比如打电话时从拿v电话拨号到挂断电话这中间的一pdq程可以UC?一? session.有时候我们可以看到这L?#8220;在一个浏览器会话期间Q?#8230;…”Q这里的会话一词用的就是其本义Q是指从一个浏览器H口打开到关闭这个期? ①。最混ؕ的是“用户Q客LQ在一ơ会话期?#8221;q样一句话Q它可能指用L一pd动作Q一般情况下是同某个具体目的相关的一pd动作Q比如从d到选购 商品到结账登样一个网上购物的q程Q有时候也被称Z个transactionQ,然而有时候也可能仅仅是指一ơ连接,也有可能是指含义①Q其中的?别只能靠上下文来推断②?/p>

    然而当session一词与|络协议相关联时Q它又往往隐含?#8220;面向q接”??#8220;保持状?#8221;q样两个含义Q? “面向q接”指的是在通信双方在通信之前要先建立一个通信的渠道,比如打电话,直到Ҏ接了电话通信才能开始,与此相对的是写信Q在你把信发出去的时候你 q不能确认对方的地址是否正确Q通信渠道不一定能建立Q但对发信h来说Q通信已经开始了?#8220;保持状?#8221;则是指通信的一方能够把一pd的消息关联v来,使得 消息之间可以互相依赖Q比如一个服务员能够认出再次光的老顾客ƈ且记得上ơ这个顾客还Ơ店里一块钱。这一cȝ例子?#8220;一个TCP session”或? “一个POP3 session”③?/p>

    而到了web服务器蓬勃发展的时代Qsession在web开发语境下的语义又有了新的扩展Q它的含义是指一cȝ来在客户端与服务器之间保持状态的解决??#9315;。有时候session也用来指q种解决Ҏ的存储结构,?#8220;把xxx保存在session ?#8221;⑤。由于各U用于web开发的语言在一定程度上都提供了对这U解x案的支持Q所以在某种特定语言的语境下Qsession也被用来指代该语a的解?ҎQ比如经常把Java里提供的javax.servlet.http.HttpSessionUCؓsession⑥?/p>

    鉴于q种混ؕ已不可改变,本文中session一词的q用也会Ҏ上下文有不同的含义,请大家注意分辨?/p>

    在本文中Q用中?#8220;览器会话期?#8221;来表辑֐?#9312;Q?#8220;session机制”来表辑֐?#9315;Q?#8220;session”表达含义⑤Q用具体的“HttpSession”来表辑֐?#9317;

    二、HTTP协议与状?br />
 
?持HTTP 协议本n是无状态的Q这与HTTP协议本来的目的是相符的,客户端只需要简单的向服务器h下蝲某些文gQ无论是客户端还是服务器都没有必要纪录彼此过?的行为,每一ơ请求之间都是独立的Q好比一个顾客和一个自动售货机或者一个普通的Q非会员Ӟ大卖Z间的关系一栗?/p>

    然而聪明(或者贪心?Q的Z很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用Q就像给有线电视加上Ҏ功能一栗这U需求一斚wq HTML逐步d了表单、脚本、DOM{客L行ؓQ另一斚w在服务器端则出现了CGI规范以响应客L的动态请求,作ؓ传输载体的HTTP协议也添加了 文g上蝲? cookieq些Ҏ。其中cookie的作用就是ؓ了解决HTTP协议无状态的~陷所作出的努力。至于后来出现的session机制则是又一U在客户?与服务器之间保持状态的解决Ҏ?/p>

    让我们用几个例子来描qC下cookie和session机制之间的区别与联系。笔者曾l常ȝ一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠Q然而一ơ?消费5杯咖啡的Z微乎其微Q这时就需要某U方式来U录某位֮的消Ҏ量。想象一下其实也无外乎下面的几种ҎQ?、该店的店员很厉宻I能记住每位顾?的消Ҏ量,只要֮一走进咖啡店,店员q道该怎么对待了。这U做法就是协议本w支持状态?/p>

    2、发l顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每ơ消ҎQ如果顾客出C张卡片,则此ơ消费就会与以前或以后的消费相联pv来。这U做法就是在客户端保持状态?/p>

    3、发l顾客一张会员卡Q除了卡号之外什么信息也不纪录,每次消费Ӟ如果֮出示该卡片,则店员在店里的纪录本上找到这个卡号对应的U录d一些消费信息。这U做法就是在服务器端保持状态?/p>

    ׃HTTP协议是无状态的Q而出于种U考虑也不希望使之成ؓ有状态的Q因此,后面两种Ҏ成为现实的选择。具体来说cookie机制采用的是在客L 保持状态的ҎQ而session机制采用的是在服务器端保持状态的Ҏ。同时我们也看到Q由于采用服务器端保持状态的Ҏ在客L也需要保存一个标识, 所以session机制可能需要借助于cookie机制来达C存标识的目的Q但实际上它q有其他选择?/p>

    三、理解cookie机制

 
cookie机制的基本原理就如上面的例子一L单,但是q有几个问题需要解冻I“会员?#8221;如何分发Q?#8220;会员?#8221;的内容;以及客户如何使用“会员?#8221;?/p>

    正统的cookie分发是通过扩展HTTP协议来实现的Q服务器通过在HTTP的响应头中加上一行特D的指示以提C浏览器按照指示生成相应的cookie.然而纯_的客户端脚本如JavaScript或者VBScript也可以生成cookie.

    而cookie 的用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器查所有存储的cookieQ如果某个cookie所声明的作用范围大于等于将要请求的 资源所在的位置Q则把该cookie附在h资源的HTTPh头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示Q如果某家分店还发行了自 q会员卡,那么q这家店的时候除了要出示麦当劳的会员卡,q要出示q家店的会员卡?/p>

    cookie的内容主要包括:名字Q|q期旉Q\径和域?/p>

    其中域可以指定某一个域比如。google.comQ相当于d招牌Q比如宝z公司,也可以指定一个域下的具体某台机器比如www.google.com或者froogle.google.comQ可以用飘柔来做比?/p>

    路径是跟在域名后面的URL路径Q比?或?foo{等Q可以用某飘柔专柜做比?/p>

    路径与域合在一起就构成了cookie的作用范围?/p>

    如果不设|过期时_则表C个cookie的生命期为浏览器会话期间Q只要关闭浏览器H口Qcookie消׃。这U生命期为浏览器会话期的 cookie被称Z话cookie.会话cookie一般不存储在硬盘上而是保存在内存里Q当然这U行为ƈ不是规范规定的。如果设|了q期旉Q浏览器 ׃把cookie保存到硬盘上Q关闭后再次打开览器,q些cookie仍然有效直到过讑֮的过期时间?/p>

    存储在硬盘上的cookie 可以在不同的览器进E间׃nQ比如两个IEH口。而对于保存在内存里的cookieQ不同的览器有不同的处理方式。对于IEQ在一个打开的窗口上? Ctrl-NQ或者从文g菜单Q打开的窗口可以与原窗口共享,而用其他方式新开的IEq程则不能共享已l打开的窗口的内存cookieQ对? Mozilla Firefox0.8Q所有的q程和标{N都可以共享同Lcookie.一般来说是用javascript的window.open打开的窗口会与原H?口共享内存cookie.览器对于会话cookie的这U只认cookie不认人的处理方式l常l采用session机制的web应用E序开发者造成?大的困扰?/p>

    下面是一个goolge讄cookie的响应头的例子HTTP/1.1 302 FoundLocationQ?http://www.google.com/intl/zh-CN/Set-CookieQ? PREF=ID=0565f77e132de138QNW=1QTM=1098082649QLM=1098082649QS=KaeaCFPo49RiA_d8Q? expires=SunQ?17-Jan-2038 19Q?4Q?7 GMTQ?path=/Q? domain=.google.comContent-TypeQ?text/html

    q是使用HTTPLookq个HTTP Sniffer软g来俘LHTTP通讯U录的一部分

    览器在再次讉Kgoolge的资源时自动向外发送cookie

    用Firefox可以很容易的观察现有的cookie的g用HTTPLook配合Firefox可以很容易的理解cookie的工作原理?/p>

    IE也可以设|在接受cookie前询?/p>

    四、理解session机制

    session机制是一U服务器端的机制Q服务器使用一U类g散列表的l构Q也可能是使用散列表)来保存信息?/p>

    当程序需要ؓ某个客户端的h创徏一个session的时候,服务器首先检查这个客L的请求里是否已包含了一个session标识 - UCؓ session idQ如果已包含一个session id则说明以前已lؓ此客L创徏qsessionQ服务器按照session id把这? session索出来用(如果索不刎ͼ可能会新Z个)Q如果客Lh不包含session idQ则为此客户端创Z个sessionq且生成一个与此session相关联的session idQsession id的值应该是一个既不会重复Q又不容易被扑ֈ规律以仿造的字符Ԍq个 session id被在本ơ响应中q回l客L保存?/p>

    保存q个session id的方式可以采用cookieQ这样在交互q程中浏览器可以自动的按照规则把q个标识发挥l服务器。一般这个cookie的名字都是类g SEEESIONIDQ而。比如weblogic对于web应用E序生成的cookieQJSESSIONID= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBngQ?145788764Q它的名字就? JSESSIONID.

    ׃cookie可以被h为的止Q必L其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一U技术叫做URL重写Q就是把session id直接附加在URL路径的后面,附加方式也有两种Q一U是作ؓURL路径的附加信息,表现形式?a href="http://%e2%80%a6%e2%80%a6/xxx">http://……/xxxQjsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBngQ?145788764另一U是作ؓ查询字符串附加在URL后面Q表现Ş式ؓhttp://……/xxxQjsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBngQ?145788764 q两U方式对于用h说是没有区别的,只是服务器在解析的时候处理的方式不同Q采用第一U方式也有利于把session id的信息和正常E序参数区分开来?/p>

    Z在整个交互过E中始终保持状态,必d每个客户端可能请求的路径后面都包含这个session id.

    另一U技术叫做表单隐藏字Dc就是服务器会自动修改表单,d一个隐藏字D,以便在表单提交时能够把session id传递回服务器。比如下面的表单<form name="testform" action="/xxx"><input type="text"></form>

    在被传递给客户端之前将被改写成<form name="testform" action="/xxx"><input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBngQ?145788764"& gt;<input type="text"></form>

    q种技术现在已较少应用Q笔者接触过的很古老的iPlanet6QSunONE应用服务器的前nQ就使用了这U技术?/p>

    实际上这U技术可以简单的用对action应用URL重写来代ѝ?/p>

    在谈论session机制的时候,常常听到q样一U误?#8220;只要关闭览器,session消׃”。其实可以想象一下会员卡的例子,除非֮d对店?提出销卡,否则店家l对不会L删除֮的资料。对session来说也是一LQ除非程序通知服务器删除一个sessionQ否则服务器会一直保留,E?序一般都是在用户做log off的时候发个指令去删除session.然而浏览器从来不会d在关闭之前通知服务器它要关闭Q因此服务器Ҏ不会有机会知道浏览器已经关闭Q之所 以会有这U错觉,是大部分session机制都用会话cookie来保存session idQ而关闭浏览器后这?session id消׃Q再ơ连接服务器时也无法找到原来的session.如果服务器设|的cookie被保存到盘上,或者用某U手D|写浏览器发出?HTTPh_把原来的session id发送给服务器,则再ơ打开览器仍然能够找到原来的session.

    恰恰是由于关闭浏览器不会Dsession被删除,q服务器ؓseesion讄了一个失效时_当距dL上一ơ用session的时间超q这个失效时间时Q服务器可以认为客L已经停止了活动,才会把session删除以节省存储空间?/p>

    五、理解javax.servlet.http.HttpSession

 
HttpSession是Javaq_对session机制的实现规范,因ؓ它仅仅是个接口,具体到每个web应用服务器的提供商,除了对规范支持之外,仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作ؓ例子来演C?/p>

    首先QWeblogic Server提供了一pd的参数来控制它的HttpSession的实玎ͼ包括使用cookie的开关选项Q用URL重写的开关选项Qsession?久化的设|,session失效旉的设|,以及针对cookie的各U设|,比如讄cookie的名字、\径、域Q?cookie的生存时间等?/p>

    一般情况下Qsession都是存储在内存里Q当服务器进E被停止或者重启的时候,内存里的session也会被清I,如果讄了session的持久化 Ҏ,服务器就会把session保存到硬盘上Q当服务器进E重新启动或q些信息能够被再次使用Q?Weblogic Server支持的持久性方式包括文件、数据库、客Lcookie保存和复制?/p>

    复制严格说来不算持久化保存,因ؓsession实际上还是保存在内存里,不过同样的信息被复制到各个cluster内的服务器进E中Q这样即使某个服务器q程停止工作也仍然可以从其他q程中取得session.

    cookie生存旉的设|则会媄响浏览器生成的cookie是否是一个会话cookie.默认是用会话cookie.有兴的可以用它来试验我们在W四节里提到的那个误解?/p>

    cookie的\径对于web应用E序来说是一个非帔R要的选项QWeblogic Server对这个选项的默认处理方式得它与其他服务器有明昄区别。后面我们会专题讨论?/p>

    关于session的设|参考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869

    六、HttpSession常见问题Q在本小节中session的含义ؓ⑤?#9317;的؜合)

    1、session在何时被创徏一个常见的误解是以为session在有客户端访问时p创徏Q然而事实是直到某server端程序调? HttpServletRequest.getSessionQtrueQ这L语句时才被创建,注意如果JSP没有昄的?<% @page session="false"%> 关闭sessionQ则JSP文g在编译成Servlet时将会自动加上这样一条语? HttpSession session = HttpServletRequest.getSessionQtrueQ;q也是JSP中隐含的 session对象的来历?/p>

    ׃session会消耗内存资源,因此Q如果不打算使用sessionQ应该在所有的JSP中关闭它?/p>

    2、session何时被删除综合前面的讨论Qsession在下列情况下被删除a.E序调用HttpSession.invalidateQ)Q或b. 距离上一ơ收到客L发送的session id旉间隔过了session的超时设|;或c.服务器进E被停止Q非持久sessionQ?/p>

    3、如何做到在览器关闭时删除session严格的讲Q做不到q一炏V可以做一点努力的办法是在所有的客户端页面里使用javascript代码 window.oncolose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除session.但是对于览器崩溃或者强行杀死进E这些非常规 手段仍然无能为力?/p>

    4、有个HttpSessionListener是怎么回事你可以创Llistenerȝ控session的创建和销毁事Ӟ使得在发生这L?件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listenerQ而不是相反。类似的与HttpSession有关?listenerq有 HttpSessionBindingListenerQHttpSessionActivationListener? HttpSessionAttributeListener.

    5、存攑֜session中的对象必须是可序列化的吗不是必需的。要求对象可序列化只是ؓ了session能够在集中被复制或者能够持久保存或者在必要 时server能够暂时把session交换出内存。在 Weblogic Server的session中放|一个不可序列化的对象在控制C会收C个警告。我所用过的某个iPlanet版本如果 session中有不可序列化的对象Q在session销毁时会有一个ExceptionQ很奇怪?/p>

    6、如何才能正的应付客户端禁止cookie的可能性对所有的URL使用URL重写Q包括超链接Qform的actionQ和重定向的URLQ具体做法参见[6] http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

    7、开两个览器窗口访问应用程序会使用同一个sessionq是不同的session参见W三节对cookie的讨论,对session来说是只认id不认人,因此不同的浏览器Q不同的H口打开方式以及不同的cookie存储方式都会对这个问题的{案有媄响?/p>

    8、如何防止用h开两个览器窗口操作导致的session混ؕq个问题与防止表单多ơ提交是cM的,可以通过讄客户端的令牌来解冟뀂就是在服务器每 ơ生成一个不同的idq回l客LQ同时保存在session里,客户端提交表单时必须把这个id也返回服务器Q程序首先比较返回的id与保存在 session里的值是否一_如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表C层模式的部分。需要注意的是对于?javascript window.open打开的窗口,一般不讄q个idQ或者用单独的idQ以防主H口无法操作Q徏议不要再window.open打开的窗口里做修?操作Q这样就可以不用讄?/p>

    9、ؓ什么在Weblogic Server中改变session的值后要重新调用一ơsession.setValue做这个动作主要是Z在集环境中提示Weblogic Server session中的值发生了改变Q需要向其他服务器进E复制新的session倹{?/p>

    10、ؓ什么session不见了排除session正常失效的因素之外,服务器本w的可能性应该是微乎其微的,虽然W者在iPlanet6SP1加若q?补丁的Solaris版本上倒也遇到q;览器插件的可能性次之,W者也遇到q?721插g造成的问题;理论上防火墙或者代理服务器在cookie处理?也有可能会出现问题?/p>

    出现q一问题的大部分原因都是E序的错误,最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨个问题?/p>

    七、跨应用E序的session׃n

    常常有这L情况Q一个大目被分割成若干项目开发,Z能够互不q扰Q要求每个小目作ؓ一个单独的web应用E序开发,可是C最后突然发现某几个 项目之间需要共享一些信息,或者想使用session来实现SSOQsingle sign onQ,在session中保存login的用户信息,最自然的要求是应用E序间能够访问彼此的session.

    然而按照Servlet规范Qsession的作用范围应该仅仅限于当前应用程序下Q不同的应用E序之间是不能够互相讉KҎ的session的。各个应 用服务器从实际效果上都遵守了q一规范Q但是实现的l节却可能各有不同,因此解决跨应用程序session׃n的方法也各不相同?/p>

    首先来看一下Tomcat是如何实现web应用E序之间session的隔ȝQ从 Tomcat讄的cookie路径来看Q它对不同的应用E序讄的cookie路径是不同的Q这样不同的应用E序所用的session id是不同的Q因此即使在同一个浏览器H口里访问不同的应用E序Q发送给服务器的session id也可以是不同的?/p>

    Ҏq个Ҏ,我们可以推测Tomcat中session的内存结构大致如下?/p>

    W者以前用q的iPlanet也采用的是同L方式Q估计SunONE与iPlanet之间不会有太大的差别。对于这U方式的服务器,解决的思\很简单, 实际实行h也不难。要么让所有的应用E序׃n一个session idQ要么让应用E序能够获得其他应用E序的session id.

    iPlanet中有一U很单的Ҏ来实现共享一个session idQ那是把各个应用程序的cookie路径都设?Q实际上应该?NASAppQ对于应用程序来讲它的作用相当于根)?/p>

    <session-info><path>/NASApp</path></session-info>

    需要注意的是,操作׃n的session应该遵@一些编E约定,比如在session attribute名字的前面加上应用程序的前缀Q? setAttributeQ?name"Q?"neo"Q变成setAttributeQ?app1.name"Q? "neo"Q,以防止命名空间冲H,D互相覆盖?/p>

    在Tomcat中则没有q么方便的选择。在Tomcat版本3上,我们q可以有一些手D|׃nsession.对于版本4以上的TomcatQ目前笔者尚 未发现简单的办法。只能借助于第三方的力量,比如使用文g、数据库、JMS或者客LcookieQURL参数或者隐藏字D늭手段?/p>

    我们再看一下Weblogic Server是如何处理session的?/p>

    从截屏画面上可以看到Weblogic ServerҎ有的应用E序讄的cookie的\径都?Q这是不是意味着在Weblogic Server中默认的可以共享session了呢Q然而一个小实验卛_证明即不同的应用程序用的是同一个sessionQ各个应用程序仍然只能访?自己所讄的那些属性。这说明Weblogic Server中的session的内存结构可能如?/p>

    对于q样一U结构,? session机制本n上来解决session׃n的问题应该是不可能的了。除了借助于第三方的力量,比如使用文g、数据库、JMS或者客L cookieQURL参数或者隐藏字D늭手段Q还有一U较为方便的做法Q就是把一个应用程序的session攑ֈServletContext中,q样?外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下,

    应用E序A context.setAttributeQ?appA"Q?sessionQ;

    应用E序B contextA = context.getContextQ?/appA"Q;HttpSession sessionA = QHttpSessionQcontextA.getAttributeQ?appA"Q;

    值得注意的是q种用法不可ULQ因为根据ServletContext的JavaDocQ应用服务器可以处于安全的原因对于context.getContextQ?/appA"Q;q回I|以上做法在Weblogic Server 8.1中通过?/p>

    那么Weblogic ServerZ么要把所有的应用E序的cookie路径都设?呢?原来是ؓ了SSOQ凡是共享这个session的应用程序都可以׃n认证的信息。一 个简单的实验可以证明这一点,修改首先d的那个应用程序的描述Wweblogic.xmlQ把cookie路径修改?appA 讉K另外一个应用程序会重新要求dQ即使是反过来,先访问cookie路径?的应用程序,再访问修改过路径的这个,虽然不再提示dQ但是登录的用户 信息也会丢失。注意做q个实验时认证方式应该用FORMQ因为浏览器和web服务器对basic认证方式有其他的处理方式Q第二次h的认证不是通过 session来实现的。具体请参看[7] secion 14.8 AuthorizationQ你可以修改所附的CZE序来做q些试验?/p>

    八、ȝ

 
session机制本nq不复杂Q然而其实现和配|上的灵zL却使得具体情况复杂多变。这也要求我们不能把仅仅某一ơ的l验或者某一个浏览器Q服务器的经验当作普遍适用的经验,而是始终需要具体情况具体分析?/p>

    摘要Q虽然session机制在web应用E序中被采用已经很长旉了,但是仍然有很多h不清楚session机制的本质,以至不能正确的应用这一技术?本文详l讨论session的工作机制ƈ且对在Java web application中应用session机制时常见的问题作出解答?/p>



hankchen 2012-03-28 21:12 发表评论
]]>
CSS布局常用的方法:float:none|left|right Q{载)http://www.aygfsteel.com/hankchen/archive/2010/02/27/314056.htmlhankchenhankchenSat, 27 Feb 2010 05:01:00 GMThttp://www.aygfsteel.com/hankchen/archive/2010/02/27/314056.htmlhttp://www.aygfsteel.com/hankchen/comments/314056.htmlhttp://www.aygfsteel.com/hankchen/archive/2010/02/27/314056.html#Feedback0http://www.aygfsteel.com/hankchen/comments/commentRss/314056.htmlhttp://www.aygfsteel.com/hankchen/services/trackbacks/314056.htmlCSS布局常用的方法:float:none|left|right 
取|
none: 默认倹{对象不飘Q
left: 文本向对象的右?br /> right: 文本向对象的左?nbsp;

它是怎样工作的,看个一行两列的例子 
xhtml:
<div id="wrap">
<div id="column1">q里是第一?lt;/div>
<div id="column2">q里是第二列</div>
<div class="clear"></div> /*q是q背web标准意图的,只是惌明在它下面的元素需要清除Q?/
</div> 
CSS:
#wrap{width:100;height:auto;}
#column1{float:left;width:40;}
#column2{float:right;width:60;}
.clear{clear:both;}

position:static|absolute|fixed|relative
取|
static: 默认倹{无Ҏ定位Q对象遵循HTML定位规则
absolute: 对象从文档中拖出Q?span class="hilite3">left
Q?span class="hilite4">rightQtopQbottom{属性相对于其最接近的一个最有定位设|的父对象进行绝对定位。如果不存在q样的父对象Q则依据body对象。而其层叠通过z-index属性定?br /> fixed: 未支持。对象定位遵从绝?absolute)方式。但是要遵守一些规?br /> relative: 对象不可层叠Q但依?span class="hilite3">leftQ?span class="hilite4">rightQtopQbottom{属性在正常文档中偏移位置 

它来实现一行两列的例子 
xhtml:
<div id="wrap">
<div id="column1">q里是第一?lt;/div>
<div id="column2">q里是第二列</div>
</div> 
CSS:
#wrap{position:relative;/*相对定位*/width:770px;}
#column1{position:absolute;top:0;left:0;width:300px;}
#column2{position:absolute;top:0;right:0;width:470px;} 
他们的区别在? 
昄Q?span class="hilite2">float是相对定位的Q会随着览器的大小和分辨率的变化而改变,而position׃行了Q所以一般情况下q是float布局Q?br />
CSS常用布局实例

单行一?/strong>
body{margin:0px;padding:0px;text-align:center;}
#content{margin-left:auto;margin-right:auto;width:400px;} 

两行一?/strong> 
body{margin:0px;padding:0px;text-align:center;}
#content-top{margin-left:auto;margin-right:auto;width:400px;}
#content-end{margin-left:auto;margin-right:auto;width:400px;} 

三行一?/strong> 
body{margin:0px;padding:0px;text-align:center;}
#content-top{margin-left:auto;margin-right:auto;width:400px;width:370px;}
#content-mid{margin-left:auto;margin-right:auto;width:400px;}
#content-end{margin-left:auto;margin-right:auto;width:400px;}

单行两列 
#bodycenter{width:700px;margin-right:auto;margin-left:auto;overflow:auto;}
#bodycenter#dv1{float:left;width:280px;}
#bodycenter#dv2{float:right;width:420px;} 

两行两列
#header{width:700px;margin-right:auto;margin-left:auto;overflow:auto;}
#bodycenter{width:700px;margin-right:auto;margin-left:auto;overflow:auto;}
#bodycenter#dv1{float:left;width:280px;}
#bodycenter#dv2{float:right;width:420px;} 

三行两列
#header{width:700px;margin-right:auto;margin-left:auto;}
#bodycenter{width:700px;margin-right:auto;margin-left:auto;}
#bodycenter#dv1{float:left;width:280px;}
#bodycenter#dv2{float:right;width:420px;}
#footer{width:700px;margin-right:auto;margin-left:auto;overflow:auto;clear:both;} 

单行三列

l对定位 
#left{position:absolute;top:0px;left:0px;width:120px;}
#middle{margin:0px190px0px190px;}
#right{position:absolute;top:0px;right:0px;width:120px;} 

float定位
xhtml:
<div id="wrap">
<div id="column">
<div id="column1">q里是第一?lt;/div>
<div id="column2">q里是第二列</div>
<div class="clear"></div>/*用法web标准不徏议,但是C下面元素需要清除Q?/
</div>
<divid="column3">q里是第三列</div>
<divclass="clear"></div>/*用法web标准不徏议,但是C下面元素需要清除Q?/
</div> 
CSS:
#wrap{width:100;height:auto;}
#column{float:left;width:60;}
#column1{float:left;width:30;}
#column2{float:right;width:30;}
#column3{float:right;width:40;}
.clear{clear:both;} 

float定位?/strong>
xhtml
<div id="center"class="column">
<h1>Thisisthemaincontent.</h1>
</div>
<div id="left"class="column">
<h2>Thisistheleftsidebar.</h2>
</div>
<div id="right"class="column">
<h2>Thisistherightsidebar.</h2>
</div>
CSS
body{
margin:0;
padding-left:200px;/*LCfullwidth*/
padding-right:190px;/*RCfullwidth CCpadding*/
min-width:200px;/*LCfullwidth CCpadding*/
}
.column{
position:relative;
float:left;
}
#center{
width:100;
}
#left{
width:200px;/*LCwidth*/
right:200px;/*LCfullwidth*/
margin-left:-100;
}
#right{
width:190px;/*RCwidth*/
margin-right:-100;
}

/***IEFix***/
*html#left{
left:190px;/*RCfullwidth*/
}

两行三列 
xhtml:

<div id="header">q里是顶?lt;/div>
<div id="warp">
<div id="column">
<div id="column1">q里是第一?lt;/div>
<div id="column2">q里是第二列</div>
<div class="clear"></div>
</div>
<div id="column3">q里是第三列</div>
<div class="clear"></div>
</div> 
CSS:
#header{width:100;height:auto;}
#wrap{width:100;height:auto;}
#column{float:left;width:60;}
#column1{float:left;width:30;}
#column2{float:right;width:30;}
#column3{float:right;width:40;}
.clear{clear:both;} 

三行三列 
xhtml:
<div id="header">q里是顶?lt;/div>
<div id="wrap">
<div id="column">
<div id="column1">q里是第一?lt;/div>
<div id="column2">q里是第二列</div>
<div class="clear"></div>
</div>
<div id="column3">q里是第三列</div>
<div class="clear"></div>
</div>
<div id="footer">q里是底部一?lt;/div>
CSS:
#header{width:100;height:auto;}
#wrap{width:100;height:auto;}
#column{float:left;width:60;}
#column1{float:left;width:30;}
#column2{float:right;width:30;}
#column3{float:right;width:40;}
.clear{clear:both;}
#footer{width:100;height:auto;} 

PS:q里列出的是常用的例子,而非研究之用Q对一每个盒子Q我都没有设|margin,padding,boeder{属性,是因为我个h觉得Q含有宽度定位的时候,最好不好用C们,除非必不得已Q因为如果不是这L话,解决览器兼定w题,会让你头|而且产生一pdCSS代码Q我觉得q样的效率和效果都不好! 

CSS布局高技?/strong>
margin和paddingL有可能要用到Q而生的问题如何解决呢?׃览器解释容器宽度的Ҏ不同Q?br /> IE6.0FirefoxOpera{是
真实宽度=width padding border margin
IE5.X
真实宽度=width-padding-border-margin 

IE中有动对象的双倍距MBUGQIEDoubledFloat-MarginBugQ?q里q需要具体问题具体解冻I下面是解军_法www.forest53.com/tutorials/tutorials_show.asp?id=31

很明显,W一U下很完的布局在第二种情况下后果是很凄惨的Q?nbsp;
解决的方法是hack 
div.content{
width:400px;//q个是错误的widthQ所有浏览器都读C
voice-family:"\"}\"";//IE5.X/win忽略?\"}\""后的内容
voice-family:inherit;
width:300px;//包括IE6/win在内的部分浏览器dq句Q新的数?300px)覆盖掉了旧的
}
html>body.content{//html>body是CSS2的写?br /> width:300px;//支持CSS2该写法的览?非IE5)有幸d了这一?br /> }

div.content{
width:300px!important;//q个是正的widthQ大部分支持!important标记的浏览器使用q里的数?br /> width(I格)/**/:400px;//IE6/win不解析这句,所以IE6/win仍然认ؓwidth的值是300pxQ而IE5.X/windq句Q新的数?400px)覆盖掉了旧的Q因?important标记对他们不起作?br /> }
html>body.content{//html>body是CSS2的写?br /> width:300px;//支持CSS2该写法的览器有q读Cq一?br /> } 

列等高技?/strong>
n行n列布局Q每列高度(事先q不能确定哪列的高度Q的相同Q是每个设计师追求的目标Q做法有Q背景图填充、加JS脚本?br /> Ҏ和容器溢出部分隐藏和列的负底边界和正的内补丁相结合的Ҏ?br />
背景囑֡充法Q?/strong>
xhtml:
<div id="wrap">
<div id="column1">q是W一?lt;/div>
<div id="column1">q是W二?lt;/div>
<div class="clear"></div>
</div>
css:
#wrap{width:776px;background:url(bg.gif)repeat-y300px;}
#column1{float:left;width:300px;}
#column2{float:right;width:476px;}
.clear{clear:both;} 

是一个npx宽的一张图片在外部容器U向重复Q定位到两列交错的位|纵向重复,在视觉上产生了两列高度一L错觉?/font>

hankchen 2010-02-27 13:01 发表评论
]]>
IE7不支持min-widthQ?/title><link>http://www.aygfsteel.com/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.aygfsteel.com/hankchen/archive/2010/02/27/314049.html</guid><wfw:comment>http://www.aygfsteel.com/hankchen/comments/314049.html</wfw:comment><comments>http://www.aygfsteel.com/hankchen/archive/2010/02/27/314049.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.aygfsteel.com/hankchen/comments/commentRss/314049.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/hankchen/services/trackbacks/314049.html</trackback:ping><description><![CDATA[最q做一个项目,发现有个面讄<font style="background-color: #cce8cf">style="min-width:1000px;"</font>在IE7中无效。这个不应该啊,因ؓ以前做的很多面都可以的Q这ơؓ什么就不行了呢Q?br /> 后来发现?font style="background-color: #cce8cf"><!DOCTYPE>声明惹的。将声明Q?br /> <font style="background-color: #cce8cf"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"></font>改ؓQ?br /> <font style="background-color: #cce8cf"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">卛_?br /> 记录下来备录?br /> </font><br /> </font><br /> <br /> <img src ="http://www.aygfsteel.com/hankchen/aggbug/314049.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/hankchen/" target="_blank">hankchen</a> 2010-02-27 10:50 <a href="http://www.aygfsteel.com/hankchen/archive/2010/02/27/314049.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ٰ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ˮ</a>| <a href="http://" target="_blank">ƽɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ͨ</a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">书</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ѧ</a>| <a href="http://" target="_blank">ˮ</a>| <a href="http://" target="_blank">ϸ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ߺ</a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">пǰ</a>| <a href="http://" target="_blank">봨</a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank">Ҵ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">е</a>| <a href="http://" target="_blank">̽</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>