a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 205|回复: 0

[专业语言] Java认证:对session和cookie的一些理解(3)

[复制链接]
发表于 2012-8-4 12:44:44 | 显示全部楼层 |阅读模式
Java认证:对session和cookie的一些理解(3)
0 k/ \* f% z( ]: S" c9 M十二、session的机制3 [, O: b& t# @# q6 u& g
*************************************************************************************
1 E% L& _( {9 Usession机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存息。& w) Y: ^9 {) f
但程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否包含了一个session标识-称为 session id,如果已经包含一个session id则说明以前已经为此客户创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的session对象,但用户人为地在请求的URL后面附加上一个JSESSION的参数)。如果客户请求不包含session id,则为此客户创建一个session并且同时生成一个与此session相关联的session id,这个session id将在本次响应中返回给客户端保存。) a) b. F. j% k1 ~7 X9 D0 S+ |" m
*************************************************************************************
9 ~2 x* d6 V) u$ D0 ~# [0 w十三、保存session id的几种方式1 m. G/ X% k1 W5 }4 i* F4 C+ w
*************************************************************************************  B3 K! y. X8 h+ u9 h! H
A.保存session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。  N& M# k" ]9 w7 R" }
B. 由于cookie可以被人为的禁止,必须有其它的机制以便在cookie被禁止时仍然能够把session id传递回服务器,经常采用的一种技术叫做URL重写,就是把session id附加在URL路径的后面,附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。网络在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。
2 f, y2 x% C/ F4 ]2 tC.另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
3 Z4 s. B5 a! G4 d; t4 A*************************************************************************************7 w- q/ d; q" a' j- I3 b! n
十四、session什么时候被创建4 ?+ Q) ?- V4 e0 w* b) F* K
*************************************************************************************' z$ y5 L, m* ]) G$ Q
一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建。
6 x$ k/ [' q  ^( L. D2 m3 C8 a注意如果JSP没有显示的使用 《% @page session=“false”%》 关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句 HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。+ N8 X8 b3 f5 }- ^
由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。0 B: \8 @" y/ v. K2 W
*************************************************************************************2 `" R/ l$ Y; y. E' ~
十五、session何时被删除
( [) W/ ?0 P: p*************************************************************************************; G! \- }$ E0 w8 ?8 A
session在下列情况下被删除:  l+ y: p# J# h* s( R( G2 I
A.程序调用HttpSession.invalidate()
* J! A5 }' Q$ w4 qB.距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间4 @1 P0 M+ H0 i/ t" J
C.服务器进程被停止/ E: U) l4 @0 c! m
再次注意关闭浏览器只会使存储在客户端浏览器内存中的session cookie失效,不会使服务器端的session对象失效,除非此时Server端刚好session失效时间到了。
( V: C  M) h  G$ A: g( D*************************************************************************************
" `0 K! S* A0 B! j0 r3 W4 w. [( w: O: U: q9 x! O8 ]

) @1 y! u% R4 Q9 ^十六、URL重写有什么缺点
0 ^9 [' ]% N. h*************************************************************************************
. r6 m. |4 o0 \; |: L0 n! L! F9 |对所有的URL使用URL重写,包括超链接,form的action,和重定向的URL。每个引用你的站点的URL,以及那些返回给用户的URL(即使通过间接手段,比如服务器重定向中的Location字段)都要添加额外的信息。
5 l7 v4 [- {$ c) D0 X2 W. c0 ]这意味着在你的站点上不能有任何静态的HTML页面(至少静态页面中不能有任何链接到站点动态页面的链接)。因此,每个页面都必须使用servlet或 JSP动态生成。即使所有的页面都动态生成,如果用户离开了会话并通过书签或链接再次回来,会话的信息都会丢失,因为存储下来的链接含有错误的标识信息-该URL后面的SESSION ID已经过期了。
0 E, q* X8 F7 \, s7 u*************************************************************************************8 |$ G  X2 @+ a
十七、使用隐藏的表单域有什么缺点
1 |% U& ~4 G1 q*************************************************************************************2 t) h+ @8 ~; l; o- z
仅当每个页面都是有表单提交而动态生成时,才能使用这种方法。单击常规的《A HREF.。》超文本链接并不产生表单提交,因此隐藏的表单域不能支持通常的会话跟踪,只能用于一系列特定的操作中,比如在线商店的结账过程。
( M+ ?1 y# n: D2 a*************************************************************************************
7 C- W( d) V( {十八、会话跟踪的基本步骤( O4 a) w# M+ B4 q
*************************************************************************************
) K* D$ V  k% t1.访问与当前请求相关的会话对象
2 j% f: y! p1 r1 i! y, Y' t2.查找与会话相关的信息
1 K: a) Q3 F! S: f* M$ r3.存储会话信息
: l9 e4 k8 |7 _4.废弃会话数据2 x8 E$ K/ r4 b& ^; V
*************************************************************************************9 E9 D6 k& i& q& y9 d5 S1 @
十九、getSession()/getSession(true)、getSession(false)的区别- N  D% ]2 _  m, a
*************************************************************************************
/ O0 L. w- [1 a6 |1 _getSession()/getSession(true):当session存在时返回该session,否则新建一个session并返回该对象) W, Y, u* L' k* D- l0 D
getSession(false):当session存在时返回该session,否则不会新建session,返回null。
% U" ?+ y9 ?3 I, ?*************************************************************************************1 s5 x; \2 [* o) x5 R$ {! b, b
二十、如何将信息于会话关联起来
' e/ |4 m! X5 x/ ~2 i6 B" k7 H3 @" D" _*************************************************************************************
9 _! i* x9 E8 p! R  I" w9 V( ~1 r- psetAttribute方法会替换上次setAttribute中设定的值;如果想要在不提供任何代替的情况下移除某个值,则应使用 removeAttribute。这个方法会触发所有实现了HttpSessionBindingListener接口的值的valueUnbound方法。
; `" @' ]3 S8 _% M6 K. O% x*************************************************************************************
$ m9 g5 X' e+ S& n/ u8 B/ b/ ~  S! Z二十一、会话属性的类型有什么限制吗
* _: X: s5 }0 h; q$ H# i*************************************************************************************1 a. T: j2 \- U/ `
通常会话属性的类型只要是Object就可以了。除了null或基本类型,如int,double,boolean。如果要使用基本类型的值作为属性,必须将其转换为相应的封装类对象。
' b5 q- w2 u! M# Q; N*************************************************************************************. A4 ~0 r. H  X" i
二十二、如何废弃会话数据
: C+ ]5 ]0 j! W7 |. n) z*************************************************************************************1 ^/ [  k6 M  C- ?
A.只移除自己编写的servlet创建的数据:
" ^. f% V) L* q; t) G' [调用removeAttribute(“key”)将指定键关联的值废弃
3 H  g# G4 u) G# h+ w4 `B.删除整个会话(在当前Web应用中):# X3 H8 H% E: {' t7 S
调用invalidate,将整个会话废弃掉。这样做会丢失该用户的所有会话数据,而非仅仅由我们servlet或JSP页面创建的会话数据9 X7 D8 D, f: ]  u1 |/ ]! l
C.将用户从系统中注销并删除所有属于他(或她)的会话
. |. Z% C- S  E- J( ^- c& o' A  I! `调用logOut,将客户从Web服务器中注销,同时废弃所有与该用户相关联的会话(每个Web应用至多一个)。这个操作有可能影响到服务器上多个不同的Web应用。, F  r$ J2 v3 [
*************************************************************************************
8 k4 J- V! _9 Y% a; Y4 ]2 x7 o二十三、使用isNew来判断用户是否为新旧用户的错误做法
4 d& k3 u/ u3 x*************************************************************************************6 ~$ {* q/ O+ ?0 P4 B# X. a0 g
public boolean isNew()方法如果会话尚未和客户程序(浏览器)发生任何联系,即服务器端程序还没有返回客户端时,则这个方法返回true,这一般是因为会话是新建的,不是由输入的客户请求所引起的。但如果isNew返回false,只不过是说明他之前曾经访问Web应用,并不代表他们曾访问过我们的servlet 或JSP页面。
, B6 _, ?( R# Z3 {" A9 m因为session是与用户相关的,在用户之前访问的每一个页面都有可能创建了会话。因此isNew为false只能说用户之前访问过该Web 应用,session可以是当前页面创建,也可能是由用户之前访问过的页面创建的。正确的做法是判断某个session中是否存在某个特定的key且其 value是否正确。(待测试)
1 @* F; ]+ V5 z, p) ?2 v*************************************************************************************
- |1 F* \) b! u5 G二十四、Cookie的过期和Session的超时有什么区别
- ^$ B+ n4 r- z! a*************************************************************************************
1 S! ?4 I- R( n) T2 H8 s会话的超时由服务器来维护,它不同于Cookie的失效日期。
- X0 Q% i6 @/ R' e& i首先,会话一般基于驻留内存的cookie不是持续性的cookie,因而也就没有截至日期。即使截取到JSESSIONID cookie,并为它设定一个失效日期发送出去。浏览器会话和服务器会话也会截然不同。* m8 b9 J1 P* u/ u, I) A) z1 m7 u* _; j
*************************************************************************************
$ W7 ]* S2 t# O二十五、session cookie和session对象的生命周期是一样的吗/ w) r* r1 C8 N) X9 Y) `1 Q
*************************************************************************************
- P$ s$ P+ h6 l6 Q3 r! @当用户关闭了浏览器虽然session cookie已经消失,但session对象仍然保存在服务器端,直到其失效时间。
* a* [1 C, N. a4 a& n  a0 y- h*************************************************************************************2 D7 j# u# C2 G

0 q- F6 `$ C  g3 b7 n
* o0 M  d. S' h9 B* ^! M3 P二十六、是否只要关闭浏览器,session就消失了7 U# T& T( N! u
*************************************************************************************
( Q$ f5 ^$ f, E* {; @4 v, O' I程序一般都是在用户做log off的时候发个指令去删除session,然而浏览器从来不会主动在关闭之前通知服务器它将要被关闭,因此服务器根本不会有机会知道浏览器已经关闭。服务器会一直保留这个会话对象直到它处于非活动状态超过设定的间隔为止。
) n% _* b+ Q7 G& t1 q之 所以会有这种错误的认识,是因为大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个session id就消失了,再次连接到服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的 HTTP请求报头,把原来的session id发送到服务器,则再次打开浏览器仍然能够找到原来的session。恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为session 设置了一个失效时间,当距离客户上一次使用session的时间超过了这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。
1 @+ V: Z3 Y) E/ c/ d6 u由此我们可以得出如下结论:
! V9 t% {/ F3 H! }5 x5 H- I/ j关闭浏览器,只会是浏览器端内存里的session cookie消失,但不会使保存在服务器端的session对象消失,同样也不会使已经保存到硬盘上的持久化cookie消失。
+ E/ ^7 p; j( S9 N8 r7 {补充:那如何做到在浏览器关闭时删除session呢 ?
2 s4 N; e; l" b0 h# Y严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。
" Y, c% p% ]. O# W7 N- ]4 t*************************************************************************************% G$ x- o6 U; K" y  C. G
二十七、打开两个浏览器窗口访问应用程序会使用同一个session还是不同的session
3 L- B+ Y3 P1 J% V, c  l2 ]& m. U*************************************************************************************
0 h8 ^# C6 `! Y. P2 z通常session cookie是不能跨窗口使用的,当你新开了一个新的浏览器窗口进入相同页面时,系统会赋予你一个新的session id,这样我们信息共享的目的就达不到了。对session来说是只认id不认人,因此不同的浏览器,不同的窗口打开方式以及不同的cookie存储方式 (如会话cookie和持久cookie)都会对这个问题的答案有影响。" I, R6 O; L) _
(在IE下测试,打开两个浏览器(不是新建窗口,是直接启动两次浏览器),得到的SessionID也是不一样)
* N9 z/ ^, c8 h8 |: [2 i7 Q要 实现跨窗口的会话跟踪,我们可以先把session id保存在persistent cookie中(通过设置session的最大有效时间),然后在新窗口中读出来,就可以得到上一个窗口的session id了,这样通过session cookie和persistent cookie的结合我们就可以实现了跨窗口的会话跟踪。(待测试)
* r& p9 ~* e+ C" J" I8 _6 D; v* o$ m/ E*************************************************************************************% n* J5 U( ~, }9 h$ X5 o
二十八、如何使用会话显示每个客户的访问次数, P* o0 @7 B3 `2 Y
*************************************************************************************
- [4 W; e  g  o8 D由于客户的访问次数是一个整型的变量,但session的属性类型中不能使用int,double,boolean等基本类型的变量,所以我们要用到这些基本类型的封装类型对象作为session对象中属性的值。4 V0 w6 I( Q( g; P
但像Integer是一种不可修改(Immutable)的数据结构:构建后就不能更改。这意味着每个请求都必须创建新的Integer对象,之后使用setAttribute来覆盖之前存在的老的属性的值。例如:
  m  y) K; U/ H% i) ?, I. s5 m9 GInteger value = (Integer)request.getSession().getAttribute(“cout”);
/ ~9 p: p: b5 Z+ \4 K3 hif (value == null){& k0 r* C, H2 [8 N
value = new CountClass(…); // 新创建一个不可更改对象+ z2 o5 A2 @9 o
}else{
* e+ B; M4 G  r  \% {, Evalue = new CountClass(calculated(value)); // 对value重新计算后创建新的对象$ c! u7 Q, L* w
}
4 J* {5 P) {# t* ~. s, J4 hrequest.getSession().setAttribute(“cout”,value);// 使用新创建的对象覆盖原来的老的对象; d; ~+ W+ ]$ C5 u! O+ n4 W
*************************************************************************************
# v0 r0 B# ]3 J7 o1 M二十九、如何使用会话累计用户的数据
2 Q/ p4 [4 j8 M6 t) i# `  }" p*************************************************************************************
- L7 u  t/ x0 Y3 D5 G& }使用可变的数据结构,比如数组、List、Map或含有可写字段的应用程序专有的数据结构。通过这种方式,除非首次分配对象,否则不需要调用setAttribute。例如:
8 u& R5 G8 ]/ X3 Y7 y! VList list_check = (List) request.getSession().getAttribute(“ids_go”);
  L' h1 S' s0 w4 Bif(list_check = = null){
1 |9 Z# w* G7 O/ K/ _( Ilist_check = new List(。..);  c5 M4 C& ~  n" _' ?/ |7 L  p+ K4 B
request.getSession().setAttribute((“ids_go”,list_check );
% [+ R0 e$ `  f8 a: f}else{+ }/ S5 j8 J# R& r9 F
list_check .clear();// 如果已经存在该对象则更新其属性而不需重新设置属性+ G4 p5 k- x) |- g6 k
}' E0 `7 u$ t' @( P4 I+ r/ Q3 m
List list_check1 = (List) request.getSession().getAttribute(“ids_go”);" N5 ^9 V1 V: M$ p( m! l! E! b
System.out.println(list_check1.size());//此时size为0* L4 _  v) {% A8 \& j. k7 W* l3 y5 Q" I5 P
*************************************************************************************6 y+ [) h% V  }+ Q$ {# P
三十、不可更改对象和可更改对象在会话数据更新时的不同处理6 U2 _' n& D7 T6 F% C0 g
*************************************************************************************' W1 w% K4 N& c# N, k0 n# c. D
不可更改对象因为一旦创建之后就不能更改,所以每次要修改会话中属性的值的时候,都需要调用setAttribute(“someIdentifier”,newValue)来代替原有的属性的值,否则属性的值不会被更新。, ?5 g* U% o! b) \3 c/ Z
可更改对象因为其自身一般提供了修改自身属性的方法,所以每次要修改会话中属性的值的时候,只要调用该可更改对象的相关修改自身属性的方法就可以了,这意味着我们就不需要调用setAttribute方法了。# O4 I; N5 Q7 i8 a; l7 @9 d
总结
8 ^" U1 l4 `' P+ wsession机制本身并不复杂,然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器,服务器的经验当作普遍适用的。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-10 13:41 , Processed in 0.162886 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表