java关键字

cookies
网站可以利用cookies跟踪统计用户访问该网站的习惯,比如什么时间访问,访问了哪些页面,在每个网页的停留时间等。利用这些信息,一方面是可以为用户提供个性化的服务,另一方面,也可以作为了解所有用户行为的工具,对于网站经营策略的改进有一定参考价值。例如,你在某家航空公司站点查阅航班时刻表,该网站可能就创建了包含你旅行计划的Cookies,也可能它只记录了你在该站点上曾经访问过的Web页,在你下次访问时,网站根据你的情况对显示的内容进行调整,将你所感兴趣的内容放在前列。这是高级的Cookie应用。目前Cookies 最广泛的是记录用户登录信息,这样下次访问时可以不需要输入自己的用户名、密码了——当然这种方便也存在用户信息泄密的问题,尤其在多个用户共用一台电脑时很容易出现这样的问题。
另外,有人认为网站利用cookies可能存在侵犯用户隐私的问题,但由于大多用户对此了解不多,而且这种对用户个人信息的利用多数作为统计数据之用,不一定造成用户的直接损失,因此现在对于cookies与用户隐私权的问题并没有相关法律约束,很多网站仍然在利用cookie跟踪用户行为,有些程序要求用户必须开启cookie才能正常应用。IE浏览器用户可以通过“隐私”选项中的隐私设置的高低来决定是否允许网站利用cookie跟踪自己的信息,从全部限制到全部允许,或者限制部分网站,也可以通过手动方式对具体的网站设置允许或者禁止使用cookies进行编辑。IE浏览器的默认设置是 “中级”-对部分网站利用cookie有限制。个人电脑的cookies设置(对IE浏览器而言)可通过菜单“工具-Internet选项-隐私”来查看和修改。

生存周期
Cookie可以保持登录信息到用户下次与服务器的会话,换句话说,下次访问同一网站时,用户会发现不必输入用户名和密码就已经登录了(当然,不排除用户手工删除Cookie)。而还有一些Cookie在用户退出会话的时候就被删除了,这样可以有效保护个人隐私。

Cookie在生成时就会被指定一个Expire值,这就是Cookie的生存周期,在这个周期内Cookie有效,超出周期Cookie就会被清除。有些页面将Cookie的生存周期设置为“0”或负值,这样在关闭浏览器时,就马上清除Cookie,不会记录用户信息,更加安全。

识别功能 编辑
如果 在一台计算机中安装多个浏览器,每个浏览器都会在各自独立的空间存放cookie。因为cookie中不但可以确认用户,还能包含计算机和浏览器的信息,所以一个用户用不同的浏览器登录或者用不同的计算机登录,都会得到不同的cookie信息,另一方面,对于在同一台计算

机上使用同一浏览器的多用户群,cookie不会区分他们的身份,除非他们使用不同的用户名登录。


coolies的缺点
1识别不精确
2隐私易泄露,信息不安全,有广告


config
config是显示配置信息命令。config对象对应于javax.servlet.ServletConfig类,此类位于servlet-api.jar包中。web容器在初始化时使用一个ServletConfig(即config)对象向JSP页面传递信息,此配置信息包括初始化参数(在当前Web应用的应用部署描述文件web.xml中定义)以及表示Servlet或JSP页面所属Web应用的ServletContext对象。
config对象的几个方法:

(1) public String getParameter(String name);

返回制定的名称name初始化参数的值,如果参数不存在则返回null。

(2) public java.util.Enumeration getinitParameterNames();

得到所有初始化参数名称的枚举。

(3) public ServletContext getServletContext();

返回Servlet或JSP页面所属的ServletContext的一个引用。

(4) public String getServletName();

返回Servlet实例或JSP页面的名称,此名称可以在Web应用部署描述文件中指定,对于一个未注册(也就是未命名)Servlet实例或JSP页面,将返回该Servlet类的类名。





HttpServletRequest,HttpServletResponse:这两个属性的作用范围最小。
时间上:只是本身请求和应答完成就失效,当然转发是把当前的request对象取出来传给另一个资源,其实本身的request对象还是只生存到本次请求结束,response也同样。
空间上:只能发送请求的客户端有效。
HttpSession:一次连结到客户端关闭,时间作用范围比上面两个大,空间任用范围相同。
ServletConfig:从一个servlet被实例化后,对任何客户端在任何时候访问有效,但仅对本servlet有效,一个servlet的ServletConfig对象不能被另一个servlet访问。
ServletContext:对任何servlet,任何人在任何时间都有效,这才是真正全局的对象。
那么,ServletConfig参数和ServletContext参数到底应该如何使用,如何取得?
一般来说,对整个应用的配置,为了不使用“硬编码”,应该配置为ServletContext参数,比如字符集设定。
< web-app>
.................
< init-param>
< param-name>charset< /param-name>
< param-value>GB2312< /param-value>
< /init-param>
.................
< /web-app>


注意以上格式只是2。0以后的标准格式,旧容器(引擎)采用服务商自己的格式配置。注意它的父元素应该是< web-app>也就是说它是对一个应用作用的。
而如果只有一个特定的servlet要设定的参数,其它servlet不能共享,应该配置为ServletConfig参数,如一个读取附件的servlet要用到绝对目录

,而别的servlet不会用到:
< servlet>
< servlet-name>GetAtt< /servlet-name>
< servlet-class>mail.GetAttServlet< /servlet-class>
< init-param>
< param-name>absPath< /param-name>
< param-value>/usr/mail/ax/axman/Maildir/< /param-value>
< /init-param>
< /servlet>



不用说,因为在< servlet>标签中已经指定了name和class,也就是说只有mail.GetAttServlet这个servlet中才能取到path,而别的Servlet是不能取到的。
那么如何访问这两个对象的参数呢?
访问ServletConfig参数:
首先要取得ServletConfig对象,然后调用它的getInitParameter();方法。要访问ServletConfig对象,jsp中直接使用config内置对象,但因为你的JSP编译后的servlet一般不会被加到web.xml中的,所以一般不会通过jsp来取对本JSP编译后的servlet的配置参数,那么在servlet中要得到ServletConfig对象有两种方法:
在inii()方法中取到:通过init的重载方法传递
public class Test extends HttpServlet
{
ServletConfig config;
public void init(ServletConfig config) throws ServletException {
this.config = config;
}
..................
}



然后在下面的方法中就可以访问config对象。但要注意,为了确保能从构造方法中到到当前servlet的config对象,应该调用父类的构造方法:
public class Test extends HttpServlet
{
ServletConfig config;
public void init(ServletConfig config) throws ServletException {
super.init(config);
this.config = config;
}
..................
}


通过getServletConfig()方法直接到时,这样做的好处是不必调手工传递属性,想在任何时候都可以得到。
还有第三种方法,要自己实现一些接口,这里作为一般讨论就不介绍了。
要访问ServletContext对象,只要从现有的ServletConfig对象getServletContext()就可以了,然后调用它的getInitParameter()方法就可以获取它的参数。
按说:ServletContext对象的作用域比ServletConfig作用域大,为什么要从ServletConfig中到得ServletContext对象呢?我个人认为:容器保存了很多个ServletContext对象,请求时容器到底取哪一个给你呢?那就取其中包含ServletConfig信息的那个给你,就是说取ServletConfig对象的父级对象。就好象HttpSession要从requset中取得一样,就是取那个包含当前requese对象的session对象给你,这只是我的个人想法,还没有来得及看具体实现。反正就这么用吧。


Session
Session,在计算机中,尤其是在网络应用中,称为“会话”。具体到Web中的Session指的就是用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费

的时间。
Session直接翻译成中文比较困难,一般都译成时域。在计算机专业术语中,Session是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经过的时间以及如果需要的话,可能还有一定的操作空间。

具体到Web中的Session指的就是用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间。因此从上述的定义中我们可以看到,Session实际上是一个特定的时间概念。

需要注意的是,一个Session的概念需要包括特定的客户端,特定的服务器端以及不中断的操作时间。A用户和C服务器建立连接时所处的Session同B用户和C服务器建立连接时所处的Session是两个不同的Session。

session的工作原理

(1)当一个session第一次被启用时,一个唯一的标识被存储于本地的cookie中。

(2)首先使用session_start()函数,PHP从session仓库中加载已经存储的session变量。

(3)当执行PHP脚本时,通过使用session_register()函数注册session变量。

(4)当PHP脚本执行结束时,未被销毁的session变量会被自动保存在本地一定路径下的session库中,这个路径可以通过php.ini文件中的session.save_path指定,下次浏览网页时可以加载使用。

2 使用方法 编辑
Session 是 用于保持状态的基于 Web服务器的方法。Session 允许通过将对象存储在 Web服务器的内存中在整个用户会话过程中保持任何对象。

Session 通常用于执行以下操作

存储需要在整个用户会话过程中保持其状态的信息,例如登录信息或用户浏览 Web应用程序时需要的其它信息。

存储只需要在页重新加载过程中或按功能分组的一组页之间保持其状态的对象。

Session 的作用就是它在 Web服务器上保持用户的状态信息供在任何时间从任何页访问。因为浏览器不需要存储任何这种信息,所以可以使用任何浏览器,即使是像 PDA 或手机这样的浏览器设备。

持久性方法的限制

随着越来越多用户登录,Session 所需要的服务器内存量也会不断增加。

访问 Web应用程序的每个用户都生成一个单独的 Session 对象。每个 Session 对象的持续时间是用户访问的时间加上不活动的时间。

如果每个 Session 中保持许多对象,并且许多用户同时使用 Web应用程序(创建许多 Session),则用于 Session 持久性的服务器内存量可能会很大,从而影响了可伸缩性。
3,Session周期

新的浏览器窗口启动后,开始一个新的Session,触发Global的Session_Start的调用,从第一个浏览器窗口打开的浏览器窗口不启动新的Session。Session过期后,执行页面的提交也会触发Session_Start,等于是新

的一个Session。

4,调用Session

对于Web Service,每个方法的调用都会启动一个Session,可以用下面的方法来使多个调用在同一个Session里 CWSSyscfg cwsCfg = new CWSSyscfg(); cwsCfg.CookieContainer = new System Net.CookieContainer(); CWSSyscfg是一个Web Service类,Web Service的给代理类设置CookieContainer属性,只要多个代理的CookieContainer属性是相同的值,则对这些Web Service的调用在同一个Session。可以用单例模式来实现。

5,Session数据有效期

只要页面有提交活动,则Session的所有项都会保持,页面在20分钟(默认配置)内没有任何提交活动时Session会失效。Session内存储的多个数据项是整体失效的。

6,Session的保存

在Session中如果保存的是非序列化的类比如DataView,在用SQLServer保存Session的模式下,无法使用。查看一个类是否是序列化的方法是,需看是否用[Serializable]来标记了该类.

对于 Cookie 来说,假设我们要验证用户是否登陆,就必须在 Cookie 中保存用户名和密码(可能是 md5 加密后字符串),并在每次请求页面的时候进行验证。如果用户名和密码存储在数据库,每次都要执行一次数据库查询,给数据库造成多余的负担。因为我们并不能只做一次验证。为什么呢?因为客户端Cookie 中的信息是有可能被修改的。假如你存储 $admin变量来表示用户是否登陆,$admin 为 true 的时候表示登陆,为 false 的时候表示未登录,在第一次通过验证后将 $admin 等于 true 存储在 Cookie,下次就不用验证了,这样对么?错了,假如有人伪造一个值为 true 的 $admin 变量那不是就立即取的了管理权限么?非常的不安全。

而 Session 就不同了,Session 是存储在服务器端的,远程用户没办法修改 session 文件的内容,因此我们可以单纯存储一个 $admin变量来判断是否登陆,首次验证通过后设置 $admin 值为 true,以后判断该值是否为 true,假如不是,转入登陆界面,这样就可以减少很多数据库操作了。而且可以减少每次为了验证 Cookie 而传递密码的不安全性了(session 验证只需要传递一次,假如你没有使用 SSL 安全协议的话)。即使密码进行了 md5 加密,也是很容易被截获的。

当然使用 session 还有很多优点,比如控制容易,可以按照用户自定义存储等(存储于数据库)。我这里就不多说了。

Session是什么

Session一般译作会话,牛津词典对其的解释是进行某活动连续的一段时间。从不同的层面看待session,它有着类似但不全然相同的含义。比如,在web应用的用户看来,他打开浏览器访问一个电子商务网站,登录、并完成购物直到关闭浏览器,这是一个会话。而在web应用的开发者开来,用户登录时我需要创建一个数据

结构以存储用户的登录信息,这个结构也叫做session。因此在谈论session的时候要注意上下文环境。而本文谈论的是一种基于HTTP协议的用以增强web应用能力的机制或者说一种方案,它不是单指某种特定的动态页面技术,而这种能力就是保持状态,也可以称作保持会话。

为什么需要session

谈及session一般是在web应用的背景之下,我们知道web应用是基于HTTP协议的,而HTTP协议恰恰是一种无状态协议。也就是说,用户从A页面跳转到B页面会重新发送一次HTTP请求,而服务端在返回响应的时候是无法获知该用户在请求B页面之前做了什么的。

对于HTTP的无状态性的原因,相关RFC里并没有解释,但联系到HTTP的历史以及应用场景,我们可以推测出一些理由:

1. 设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。那个时候没有动态页面技术,只有纯粹的静态HTML页面,因此根本不需要协议能保持状态;

2. 用户在收到响应时,往往要花一些时间来阅读页面,因此如果保持客户端和服务端之间的连接,那么这个连接在大多数的时间里都将是空闲的,这是一种资源的无端浪费。所以HTTP原始的设计是默认短连接,即客户端和服务端完成一次请求和响应之后就断开TCP连接,服务器因此无法预知客户端的下一个动作,它甚至都不知道这个用户会不会再次访问,因此让HTTP协议来维护用户的访问状态也全然没有必要;

3. 将一部分复杂性转嫁到以HTTP协议为基础的技术之上可以使得HTTP在协议这个层面上显得相对简单,而这种简单也赋予了HTTP更强的扩展能力。事实上,session技术从本质上来讲也是对HTTP协议的一种扩展。

总而言之,HTTP的无状态是由其历史使命而决定的。但随着网络技术的蓬勃发展,人们再也不满足于死板乏味的静态HTML,他们希望web应用能动起来,于是客户端出现了脚本和DOM技术,HTML里增加了表单,而服务端出现了CGI等等动态技术。

而正是这种web动态化的需求,给HTTP协议提出了一个难题:一个无状态的协议怎样才能关联两次连续的请求呢?也就是说无状态的协议怎样才能满足有状态的需求呢?

此时有状态是必然趋势而协议的无状态性也是木已成舟,因此我们需要一些方案来解决这个矛盾,来保持HTTP连接状态,于是出现了cookie和session。

对于此部分内容,读者或许会有一些疑问,笔者在此先谈两点:

1. 无状态性和长连接

可能有人会问,现在被广泛使用的HTTP1.1默认使用长连接,它还是无状态的吗?

连接方式和有无状态是完全没有关系的两回事。因为状态从某种意义上来讲就是数据,而连接方式只是决定了

数据的传输方式,而不能决定数据。长连接是随着计算机性能的提高和网络环境的改善所采取的一种合理的性能上的优化,一般情况下,web服务器会对长连接的数量进行限制,以免资源的过度消耗。

2. 无状态性和session

Session是有状态的,而HTTP协议是无状态的,二者是否矛盾呢?

Session和HTTP协议属于不同层面的事物,后者属于ISO七层模型的最高层应用层,前者不属于后者,前者是具体的动态页面技术来实现的,但同时它又是基于后者的。在下文中笔者会分析Servlet/Jsp技术中的session机制,这会使你对此有更深刻的理解。

Cookie和Session

上面提到解决HTTP协议自身无状态的方式有cookie和session。二者都能记录状态,前者是将状态数据保存在客户端,后者则保存在服务端。

首先看一下cookie的工作原理,这需要有基本的HTTP协议基础。

cookie是在RFC2109(已废弃,被RFC2965取代)里初次被描述的,每个客户端最多保持三百个cookie,每个域名下最多20个Cookie(实际上一般浏览器现在都比这个多,如Firefox是50个),而每个cookie的大小为最多4K,不过不同的浏览器都有各自的实现。对于cookie的使用,最重要的就是要控制cookie的大小,不要放入无用的信息,也不要放入过多信息。

无论使用何种服务端技术,只要发送回的HTTP响应中包含如下形式的头,则视为服务器要求设置一个cookie:

Set-cookie:name=name;expires=date;path=path;domain=domain

支持cookie的浏览器都会对此作出反应,即创建cookie文件并保存(也可能是内存cookie),用户以后在每次发出请求时,浏览器都要判断当前所有的cookie中有没有没失效(根据expires属性判断)并且匹配了path属性的cookie信息,如果有的话,会以下面的形式加入到请求头中发回服务端:

Cookie: name="zj"; Path="/linkage"

服务端的动态脚本会对其进行分析,并做出相应的处理,当然也可以选择直接忽略。

这里牵扯到一个规范(或协议)与实现的问题,简单来讲就是规范规定了做成什么样子,那么实现就必须依据规范来做,这样才能互相兼容,但是各个实现所使用的方式却不受约束,也可以在实现了规范的基础上超出规范,这就称之为扩展了。无论哪种浏览器,只要想提供cookie的功能,那就必须依照相应的RFC规范来实现。所以这里服务器只管发Set-cookie头域,这也是HTTP协议无状态性的一种体现。

需要注意的是,出于安全性的考虑,cookie可以被浏览器禁用。

再看一下session的原理:

笔者没有找到相关的RFC,因为session本就不是协议层面的事物。它的基本原理是服务端为每一个session维护一

份会话信息数据,而客户端和服务端依靠一个全局唯一的标识来访问会话信息数据。用户访问web应用时,服务端程序决定何时创建session,创建session可以概括为三个步骤:

1. 生成全局唯一标识符(sessionid);

2. 开辟数据存储空间。一般会在内存中创建相应的数据结构,但这种情况下,系统一旦掉电,所有的会话数据就会丢失,如果是电子商务网站,这种事故会造成严重的后果。不过也可以写到文件里甚至存储在数据库中,这样虽然会增加I/O开销,但session可以实现某种程度的持久化,而且更有利于session的共享;

3. 将session的全局唯一标示符发送给客户端。

问题的关键就在服务端如何发送这个session的唯一标识上。联系到HTTP协议,数据无非可以放到请求行、头域或Body里,基于此,一般来说会有两种常用的方式:cookie和URL重写。

1. Cookie

读者应该想到了,对,服务端只要设置Set-cookie头就可以将session的标识符传送到客户端,而客户端此后的每一次请求都会带上这个标识符,由于cookie可以设置失效时间,所以一般包含session信息的cookie会设置失效时间为0,即浏览器进程有效时间。至于浏览器怎么处理这个0,每个浏览器都有自己的方案,但差别都不会太大(一般体现在新建浏览器窗口的时候);

2. URL重写

所谓URL重写,顾名思义就是重写URL。试想,在返回用户请求的页面之前,将页面内所有的URL后面全部以get参数的方式加上session标识符(或者加在path info部分等等),这样用户在收到响应之后,无论点击哪个链接或提交表单,都会在再带上session的标识符,从而就实现了会话的保持。读者可能会觉得这种做法比较麻烦,确实是这样,但是,如果客户端禁用了cookie的话,URL重写将会是首选。

到这里,读者应该明白我前面为什么说session也算作是对HTTP的一种扩展了吧。如下两幅图是笔者在Firefox的Firebug插件中的截图,可以看到,当我第一次访问index.jsp时,响应头里包含了Set-cookie头,而请求头中没有。当我再次刷新页面时,图二显示在响应中不在有Set-cookie头,而在请求头中却有了Cookie头。注意一下Cookie的名字:jsessionid,顾名思义,就是session的标识符
1. 应用场景

Cookie的典型应用场景是Remember Me服务,即用户的账户信息通过cookie的形式保存在客户端,当用户再次请求匹配的URL的时候,账户信息会被传送到服务端,交由相应的程序完成自动登录等功能。当然也可以保存一些客户端信息,比如页面布局以及搜索历史等等。

Session的典型应用场景是用户登录某网站之后,将其登录信息放入session,在以后的每次请求中查询相

应的登录信息以确保该用户合法。当然还是有购物车等等经典场景;

2. 安全性

cookie将信息保存在客户端,如果不进行加密的话,无疑会暴露一些隐私信息,安全性很差,一般情况下敏感信息是经过加密后存储在cookie中,但很容易就会被窃取。而session只会将信息存储在服务端,如果存储在文件或数据库中,也有被窃取的可能,只是可能性比cookie小了太多。

Session安全性方面比较突出的是存在会话劫持的问题,这是一种安全威胁,这在下文会进行更详细的说明。总体来讲,session的安全性要高于cookie;

3. 性能

Cookie存储在客户端,消耗的是客户端的I/O和内存,而session存储在服务端,消耗的是服务端的资源。但是session对服务器造成的压力比较集中,而cookie很好地分散了资源消耗,就这点来说,cookie是要优于session的;

4. 时效性

Cookie可以通过设置有效期使其较长时间内存在于客户端,而session一般只有比较短的有效期(用户主动销毁session或关闭浏览器后引发超时);

5. 其他

Cookie的处理在开发中没有session方便。而且cookie在客户端是有数量和大小的限制的,而session的大小却只以硬件为限制,能存储的数据无疑大了太多。

Servlet/JSP中的Session

通过上述的讲解,读者应该对session有了一个大体的认识,但是具体到某种动态页面技术,又是怎么实现session的呢?下面笔者将结合session的生命周期(lifecycle),从源代码的层次来具体分析一下在servlet/jsp技术中,session是怎么实现的。代码部分以tomcat6.0.20作为参考。

创建

在我问过的一些从事java web开发的人中,对于session的创建时机大都这么回答:当我请求某个页面的时候,session就被创建了。这句话其实很含糊,因为要创建session请求的发送是必不可少的,但是无论何种请求都会创建session吗?错。我们来看一个例子。

众所周知,jsp技术是servlet技术的反转,在开发阶段,我们看到的是jsp页面,但真正到运行时阶段,jsp页面是会被“翻译”为servlet类来执行的,例如我们有如下jsp页面:

<%@ page language="java" pageEncoding="ISO-8859-1" session="true"%>







index.jsp





This is index.jsp page.








在我们初次请求该页面后,在对应的work目录可以找到该页面对应的java类,考虑到篇幅的原因,在此只摘录比较重要的一部分,有兴趣的读者可以亲自试一下:

......

response.setContentType("text/html;charset=ISO-8859-1");

pageContext = _jspxFactory.getPageContext(this, request, res

ponse,

null, true, 8192, true);

_jspx_page_context = pageContext;

application = pageContext.getServletContext();

config = pageContext.getServletConfig();

session = pageContext.getSession();

out = pageContext.getOut();

_jspx_out = out;



out.write("\r\n");

out.write("\r\n");

out.write("\r\n");

......

可以看到有一句显式创建session的语句,它是怎么来的呢?我们再看一下对应的jsp页面,在jsp的page指令中加入了session="true",意思是在该页面启用session,其实作为动态技术,这个参数是默认为true的,这很合理,在此显示写出来只是做一下强调。很显然二者有着必然的联系。笔者在jsp/servlet的翻译器(https://www.360docs.net/doc/8d17344534.html,piler)的源码中找到了相关证据:

......

if (pageInfo.isSession())

out.printil("session = pageContext.getSession();");

out.printil("out = pageContext.getOut();");

out.printil("_jspx_out = out;");

......

上面的代码片段的意思是如果页面中定义了session="true",就在生成的servlet源码中加入session的获取语句。这只能够说明session创建的条件,显然还不能说明session是如何创建的,本着逐本溯源的精神,我们继续往下探索。

有过servlet开发经验的应该记得我们是通过HttpServletRequest的getSession方法来获取当前的session对象的:

public HttpSession getSession(boolean create);

public HttpSession getSession();

二者的区别只是无参的getSession将create默认设置为true而已。即:

public HttpSession getSession() {

return (getSession(true));

}

那么这个参数到底意味着什么呢?通过层层跟踪,笔者终于理清了其中的脉络,由于函数之间的关系比较复杂,如果想更详细地了解内部机制,建议去独立阅读tomcat相关部分的源代码。这里我将其中的大致流程叙述一下:

1. 用户请求某jsp页面,该页面设置了session="true";

2. Servlet/jsp容器将其翻译为servlet,并加载、执行该servlet;

3. Servlet/jsp容器在封装HttpServletRequest对象时根据cookie或者url中是否存在jsessionid来决定是绑定当前的session到HttpRequest还是创建新的session对象(在请求解析阶段发现并记录jsessionid,在Request对象创建阶段将session绑定);

4. 程序按需操作session,存取数据;

5. 如果是新创建的session,在结果响应时,容器会加入Set-cookie头,以提醒浏览器要保持该会话(或者采用URL重写方式将新的链接呈现给用户)。

通过上面的叙述读者应该了解了session是何时创建的,这里再从servlet这个层面总结一下:当用户请求的servlet调用了getSession方法时,都会获取session,至于是否创建新的session取决于当前request

是否已绑定session。当客户端在请求中加入了jsessionid标识而servlet容器根据此标识查找到了对应的session对象时,会将此session绑定到此次请求的request对象,客户端请求中不带jsessionid或者此jsessionid对应的session已过期失效时,session的绑定无法完成,此时必须创建新的session。同时发送Set-cookie头通知客户端开始保持新的会话。

保持

理解了session的创建,就很好理解会话是如何在客户端和服务端之间保持的了。当首次创建了session后,客户端会在后续的请求中将session的标识符带到服务端,服务端程序只要在需要session的时候调用getSession,服务端就可以将对应的session绑定到当前请求,从而实现状态的保持。当然这需要客户端的支持,如果禁用了cookie而又不采用url重写的话,session是无法保持的。

如果几次请求之间有一个servlet未调用getSession(或者干脆请求一个静态页面)会不会使得会话中断呢?这个不会发生的,因为客户端只会将合法的cookie值传送给服务端,至于服务端拿cookie做什么事它是不会关心的,当然也无法关心。Session建立之后,客户端会一直将session的标识符传送到服务器,无论请求的页面是动态的、静态的,甚至是一副图片。

销毁

此处谈到的销毁是指会话的废弃,至于存储会话信息的数据结构是回收被重用还是直接释放内存我们并不关心。Session的销毁有两种情况:超时和手动销毁。

由于HTTP协议的无状态性,服务端无法得知一个session对象何时将再次被使用,可能用户开启了一个session之后再也没有后续的访问,而且session的保持是需要消耗一定的服务端开销的,因此不可能一味地创建session而不去回收无用的session。这里就引入了一个超时机制。Tomcat中的超时在web.xml里做如下配置:



30



上述配置是指session在30分钟没有被再次使用就将其销毁。Tomcat是怎么计算这个30分钟的呢?原来在getSession之后,都要调用它的access方法,修改lastAccessedTime,在销毁session的时候就是判断当前时间和这个lastAccessedTime的差值。

手动销毁是指直接调用其invalidate方法,此方法实际上是调用expire方法来手动将其设置为超时。

当用户手动请求了session的销毁时,客户端是无法知道服务端的session已经被销毁的,它依然会发送先前的session标识符到服务端。而此时如果再次请求了某个调用了getSession的servlet,服务端是无法根据先前的session标识符找到相应的session对象的,这是又要重新创建新的session,分配新的标识符,并告知服务端更新session标识符开始保持新的会话。

Session

的数据结构

在servlet/jsp中,容器是用何种数据结构来存储session相关的变量的呢?我们猜测一下,首先它必须被同步操作,因为在多线程环境下session是线程间共享的,而web服务器一般情况下都是多线程的(为了提高性能还会用到池技术);其次,这个数据结构必须容易操作,最好是传统的键值对的存取方式。

那么我们先具体到单个session对象,它除了存储自身的相关信息,比如id之外,tomcat的session还提供给程序员一个用以存储其他信息的接口(在类org.apache.catalina.session. StandardSession里):

public void setAttribute(String name, Object value, boolean notify)

在这里可以追踪到它到底使用了何种数据:

protected Map attributes = new ConcurrentHashMap();

这就很明确了,原来tomcat使用了一个ConcurrentHashMap对象存储数据,这是java的concurrent包里的一个类。它刚好满足了我们所猜测的两点需求:同步与易操作性。

那么tomcat又是用什么数据结构来存储所有的session对象呢?果然还是ConcurrentHashMap(在管理session的org.apache.catalina.session. ManagerBase类里):

protected Map sessions = new ConcurrentHashMap();

具体原因就不必多说了。至于其他web服务器的具体实现也应该考虑到这两点。

Session Hijack

Session hijack即会话劫持是一种比较严重的安全威胁,也是一种广泛存在的威胁,在session技术中,客户端和服务端通过传送session的标识符来维护会话,但这个标识符很容易就能被嗅探到,从而被其他人利用,这属于一种中间人攻击。

本部分通过一个实例来说明何为会话劫持,通过这个实例,读者其实更能理解session的本质。

首先,我编写了如下页面:

<%@ page language="java" pageEncoding="ISO-8859-1" session="true"%>







index.jsp





This is index.jsp page.




<%

Object o = session.getAttribute("counter");

if (o == null) {

session.setAttribute("counter", 1);

} else {

Integer i = Integer.parseInt(o.toString());

session.setAttribute("counter", i + 1);

}

out.println(session.getAttribute("counter"));

%>

">index





页面的功能是在session中放置一个计数器,第一次访问该页面,这个计数器的值初始化为1,以后每一次访问这个页面计数器都加1。计数器的值会被打印到页面。另外,为了比较简单地模拟,笔者禁用了客户端(采用firef

ox3.0)的cookie,转而改用URL重写方式,因为直接复制链接要比伪造cookie方便多了。


























一、page 对象

page对象代表JSP对象,更准确地说它代表JSP被转译后的Servlet,它可以调用Servlet类所定义的方法。

二、config 对象

config 对象里存放着一些Servlet 初始的数据结构。

config 对象实现于javax.servlet.ServletConfig 接口,它共有下列四种方法:

public String getInitParameter(name)

public java.util.Enumeration getInitParameterNames( )

public ServletContext getServletContext( )

public Sring getServletName( )

三、request 对象

request 对象包含所有请求的信息,如:请求的来源、标头、cookies和请求相关的参数值等等。

request 对象实现javax.servlet.http.HttpServletRequest接口的,所提供的方法可以将它分为四大类:

1.储存和取得属性方法;

void setAttribute(String name, Object value)设定name属性的值为value

Enumeration getAttributeNamesInScope(int scope)取得所有scope 范围的属性

Object getAttribute(String name)取得name 属性的值

void removeAttribute(String name)移除name 属性的值

2.取得请求参数的方法

String getParameter(String name) 取得name 的参数值Enumeration

getParameterNames( ) 取得所有的参数名称String[]

getParameterValues(String name) 取得所有name 的参数值

Map getParameterMap( )取得一个要求参数的Map

3.能够取得请求HTTP 标头的方法

String getHeader(String name)取得name 的标头

Enumeration getHeaderNames()取得所有的标头名称

Enumeration getHeaders(String name)取得所有name 的标头

int getIntHeader(String name)取得整数类型name 的标头

long getDateHeader(String name) 取得日期类型name 的标头

Cookie [] getCookies( ) 取得与请求有关的cookies

4.其他的方法

String getContextPath( )取得Context 路径(即站台名称)

String getMethod( )取得HTTP 的方法(GET、POST)

String getProtocol( )取得使用的协议 HTTP/1.1、HTTP/1.0 )

String getQueryString( )取得请求的参数字符串,不过,HTTP的方法必须为GET

String getRequestedSessionId( ) 取得用户端的Session ID

String getRequestURI( )取得请求的URL,但是不包括请求的参数字符串

String getRemoteAddr( )取得用户的IP 地址

String getRemoteHost( )取得用户的主机名称

int getRemotePort( )取得用户的主机端口

String getRemoteUser( ) 取得用户的名称

void etCharacterEncoding(String encoding)设定编码格式,用来解决窗体传递中文的问题

四、response 对象

resp

onse 对象主要将JSP对象 处理数据后的结果传回到客户端。

response 对象是实现javax.

servlet.http.HttpServletResponse 接口。response对象所提供的方法。

1.设定表头的方法

void addCookie(Cookie cookie)新增cookie

void addDateHeader(String name, long date)新增long类型的值到name标头

void addHeader(String name, String value)新增String类型的值到name标头

void addIntHeader(String name, int value)新增int类型的值到name标头

void setDateHeader(String name, long date)指定long类型的值到name标头

void setHeader(String name, String value)指定String类型的值到name标头

void setIntHeader(String name, int value)指定int类型的值到name标头

2.设定响应状态码的方法

void sendError(int sc)传送状态码(status code)

void sendError(int sc, String msg)传送状态码和错误信息

void setStatus(int sc)设定状态码

3.用来URL 重写(rewriting)的方法

String encodeRedirectURL(String url)对使用sendRedirect( )方法的URL予以编码

五、out 对象

out 对象能把结果输出到网页上。

out主要是用来控制管理输出的缓冲区(buffer)和输出流(output stream)。

void clear( )清除输出缓冲区的内容

void clearBuffer( )清除输出缓冲区的内容

void close( )关闭输出流,清除所有的内容

int getBufferSize( )取得目前缓冲区的大小(KB)

int getRemaining( )取得目前使用后还剩下的缓冲区大小(KB)

boolean isAutoFlush( )回传true表示缓冲区满时会自动清除;false表示不会自动清除并且产生异常处理

六、session 对象

session对象表示目前个别用户的会话(session)状况。

session对象实现javax.servlet.http.HttpSession接口,HttpSession接口所提供的方法

long getCreationTime()取得session产生的时间,单位是毫秒

String getId()取得session 的ID

long getLastAccessedTime()取得用户最后通过这个session送出请求的时间

long getMaxInactiveInterval()取得最大session不活动的时间,若超过这时间,session 将会失效

void invalidate()取消session 对象,并将对象存放的内容完全抛弃

boolean isNew()判断session 是否为"新"的

void setMaxInactiveInterval(int interval)设定最大session不活动的时间,若超过这时间,session 将会失效

七、application对象

application对象最常被使用在存取环境的信息。

因为环境的信息通常都储存在ServletContext中,所以常利用application对象来存取ServletContext中的信息。

application 对象实现javax.servlet.ServletContext 接口,ServletContext接口容器所提供的方法

int getMajorVersion( )

取得Container主要的Servlet API版本

int getMinorVersion( )取得Container次要的Servlet API 版本

String getServerInfo( )取得Container的名称和版本

String getMimeType(String file)取得指定文件的MIME 类型

ServletContext getContext(String uripath)取得指定Local URL的Application context

String getRealPath(String path)取得本地端path的绝对路径

void log(String message)将信息写入log文件中

void log(String message, Throwable throwable)将stack trace 所产生的异常信息写入log文件中

八、pageContext对象

pageContext对象能够存取其他隐含对象。

1.pageContext对象存取其他隐含对象属性的方法,此时需要指定范围的参数。

Object getAttribute(String name, int scope)

Enumeration getAttributeNamesInScope(int scope)

void removeAttribute(String name, int scope)

void setAttribute(String name, Object value, int scope)

范围参数有四个,分别代表四种范围:PAGE_SCOPE、REQUEST_SCOPE、SESSION_SCOPE、APPLICATION_SCOPE

2.PageContext对象取得其他隐含对象的方法

Exception getException( )回传目前网页的异常,不过此网页要为error page,

JspWriter getOut( )回传目前网页的输出流,例如:out

Object getPage( )回传目前网页的Servlet 实体(instance),例如:page

ServletRequest getRequest( )回传目前网页的请求,例如:request

ServletResponse getResponse( )回传目前网页的响应,例如:response

ServletConfig getServletConfig( )回传目前此网页的ServletConfig 对象,例如:config

ServletContext getServletContext( ) 回传目前此网页的执行环境(context),例如:application

HttpSession getSession( )回传和目前网页有联系的会话(session),例如:session

3.PageContext对象提供取得属性的方法

Object getAttribute(String name, int scope)回传name 属性,范围为scope的属性对象,回传类型为Object

Enumeration getAttributeNamesInScope(int scope)回传所有属性范围为scope 的属性名称,回传类型为Enumeration

int getAttributesScope(String name)回传属性名称为name 的属性范围

void removeAttribute(String name)移除属性名称为name 的属性对象

void removeAttribute(String name, int scope)移除属性名称为name,范围为scope 的属性对象

void setAttribute(String name, Object value, int scope)指定属性对象的名称为name、值为value、范围为scope

Object findAttribute(String name)寻找在所有范围中属性名称为name 的属性对象

九、exception对象

若要使用exception 对象时,必须在page 指令中设定。才能使用。

exception提供的三个方法:

getMessage( )

getLocaliz

edMessage( )、

printStackTrace(new java.io.PrintWriter(out))



















相关文档
最新文档