8、cookie管理
- cookie是小段的文本信息,web服务器将它发送到浏览器,之后,在访问同一网站或域时,浏览器又将它原封不动地返回。通过让服务器读取它之前发送给客户程序的信息,站电可以为访问者提供诸多便利,比如按照访问者之前的定制呈现该站点,或让身份可以验证的访问者可以不需要再次输入密码进入
-
cookie优点:
- 在电子商务会话中标识用户:servlet甚至提供专门用于会话跟踪的API
- 记录用户名和密码:用户注册后,就会收到包含一个唯一用户ID的cookie。客户重新连接时,这个ID自动返回,服务器对它进行检查,确定它是否为注册用户且选择了自动登录
- 定制站点:记录用户的偏好
- 定向广告:记录哪些主题引起特定用户的兴趣,显示相关广告
- cookie从不会以任何方式得到解释或执行,因而也就不能插入病毒或攻击用户的系统。此外,由于浏览器一般对每个站点只接受20个cookie,总共不超过300个,同时每个cookie限制在4K,因此cookie不能用来填满某人的硬盘或启动其他拒绝服务(denial-of-service,DoS)攻击。但是可能对隐私造成极大的威胁!应该避免用cookie存储特别敏感的信息。
- response.addCookie将cookie插入到HTTP响应报头中;读取输入的cookie,用request.getCookies返回Cookie对象的数组,循环处理这个数组,调用每个cookie的getName方法,直到找到名称与查找的名称相匹配的cookie为止,然后调用getValue方法,检查相关联的值。
-
向客户程序发送cookie:例子:
Cookie userCookie = newCookie("user", "uid123"); userCookie.setMaxAge(60*60*24*365); // Store cookie for 1 year response.addCookie(userCookie);
- 创建Cookie对象:调用Cookie的构造函数,给出cookie的名称和值,二者都是字符串,且都不应该含有空格或这些字符
[ ] ( ) = , " / ? @ : ;
;Cookie c = new Cookie("CookieName","CookieValue");
- 设置最大时效:如果希望浏览器将cookie存储在磁盘上(默认情况下cookie是会话级别的,存储在内存,退出浏览器后被删除),在cookie发送到客户程序之前,使用setMaxAge指定多长时间(秒)内cookie是合法的;
c.setMaxAge(60*60*24*7); // One week
- 将Cookie放入到HTTP响应报头(前两步只是操作服务器内存中的数据结构,并没有实际向浏览器发送任何内容,对客户程序没有任何影响):必须显示地用response.addCookie,缺少的话,cookie不会发送给浏览器;要记住,响应报头必须在任何文档内容发送到客户端之前设置。
- 创建Cookie对象:调用Cookie的构造函数,给出cookie的名称和值,二者都是字符串,且都不应该含有空格或这些字符
-
从客户端读取cookie:
String cookieName = "userID";
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for (int i=0; i<cookies.length; i++) {
Cookie cookie = cookies[i];
if(cookieName.equals(cookie.getName())) {
doSomethingWith(cookie.getValue());
}
}
}- 调用request.getCookies
- 对数组进行循环,调用每个cookie的getName方法,直到找到需要的cookie为止,调用getValue以应用程序特有的方式使用这个值。
- 属性是从服务器发送到浏览器的报头的一部分,但他们不属于由浏览器返回给服务器的报头。因而,除了名称和值外,cookie属性只适用于从服务器输入到客户端的cookie;因而,不要期望通过request.getCookies得到属性。每次都必须调用setMaxAge,还要将Cookie传递给response.addCookie
-
属性cookie属性的方法:
-
public void setComment(String comment)
:相关注释,存在于服务器,并不发送给客户程序
public String getComment() -
public void setDomain(String domainPattern)
:设置或读取cookie适用的域,domainPattern必须以点号开始
public String getDomain() -
public void setMaxAge(int lifetime)
:多久过期,负值(默认值)标明cookie仅用于当前浏览会话,指定零值则是指示浏览器删除该cookie
public int getMaxAge() -
public String getName()
:读取cookie的名称,由于名称是提供给Cookie的构造函数的,因此没有setName方法 -
public void setPath(String path)
:cookie所适用的路径;如果没有指定一个路径,浏览器只将该cookie返回给发送cookie的页面所在目录中或之下的URL;cookie.setPath(“/”)指定服务器的所有页面都应该受到该cookie
public String getPath() -
public void setSecure(boolean secureFlag)
:表明cookie是否只能通过加密连接(即SSL)发送,默认值是false,表示cookie适用于所有的连接
public boolean getSecure() -
public void setValue(String cookieValue)
:setValue方法指定与该cookie相关联的值,getValue找出这个值
public String getValue() -
public void getVersion(int version)
:cookie协议版本,默认值版本0
public int getVersion()
-
-
周期性修改cookie的值:要替换cookie之前的值,需要发送相同的cookie名称,但使用不同cookie值。只调用setValue是没有效果的,不要忘记调用response.addCookie、setMaxAge、setPath等,重新应用所有的相关cookie属性;要指示浏览器删除一个cookie,只需
setMaxAge(0)
- 使用cookie记录用户的偏好,对于简单的用户设置,可以直接将用户的偏好存储在cookie中,对于更为复杂的应用,一般在cookie中存储唯一的用户标识,而将实际的偏好存储在数据库中。
9、会话跟踪
- HTTP是“无状态”协议:客户程序每次读取Web页面,都代开web服务器的单独的连接,并且,服务器也不自动维护客户的上下文信息。对于上下文信息的缺失存在三种典型的解决方案:
- cookie:处理会话时最常使用的方式
- URL重写:客户程序在每个URL的尾部添加一些额外数据,标识当前的会话,服务器将这个标识符与它存储的用户相关数据关联起来;不能有任何静态HTML页面,至少静态页面中不能有任何链接到站点动态页面的链接。
- 隐藏的表单域
<input type="hidden" name="session" value="a1234">
在提交表单时,将指定的名称和值自动包括在GET或POST数据中。仅当每个页面都是由表单提交而动态生成时才能使用;不能支持通常的会话跟踪,只能用于特定的操作,如在线商店的结账过程。
- servlet提供了一种出色的会话跟踪解决方案:HttpSession API;所有服务器都需要支持cookie的会话跟踪。
-
会话跟踪4个基本步骤:
- 访问与当前请求相关联的会话对象:
HttpSession session = request.getSession();
存储任意用户对象的散列表;只能在发送任何文档内容到客户程序之前调用request.getSession - 查找与会话相关联的信息:
SomeClass value = (SomeClass)session.getAttribute("someIdentifier");
在调用与会话相关联的对象的方法之前,一定要检查它是否为null - 存储会话中的信息:
session.setAttribute("someIdentifier", value);
setAttribute会替换掉任何之前设定的值,如果想要在不提供任何替代的情况下移除某个值,使用removeAttribute - 废弃会话数据
- 只移除自己编写的servlet创建的数据:removeAttribute(“key”)
- 删除整个会话(在当前Web应用中):调用invalidate
- 将用户从系统中注销并删除所有属于它的会话:logout
- 访问与当前请求相关联的会话对象:
- HttpSession类的方法汇总
- public Object getAttribute(String name):从会话对象提取之前存储的值,若没有值与name关联,返回null
- public Enumeration getAttributeNames():返回会话中所有属性名
- public void setAttribute(String name, Object value):将值和名称关联
- public void removeAttribute(String name):移除与name关联的任何值
- public void invalidate():会话作废,释放所有与之相关联的对象
- public void logout():将客户从Web服务器注销,并将相关会话全部作废
- public String getId():返回每个会话对应的唯一标识符
- public boolean isNew():若会话尚未和客户程序发生任何联系,返回true,避免使用
- public long getCreationTime():返回会话首次构建的时间
- public long getLastAccessedTime():返回会话最后被客户程序访问的时间
- public int getMaxInactiveInterval()
- public void setMaxInactiveInterval(int seconds):读取或设置在没有访问的情况下,会话在被自动废弃之前应该保持多长时间,以秒为单位。负值表示会话从不超时。超时由服务器来维护,它不同于cookie的失效日期。
- 默认地,servlet容器使用cookie作为会话跟踪的底层机制;如果你使用URL重写进行会话跟踪来代替cookie,你的大部分或全部页面都必须动态生成,你站点上的任何静态HTML页面都不能含有指向自身站点动态页面的链接。
- Integer是一种immutable(不可修改)的数据结构:构建后就不能更改,这意味着每个请求都必须分配新的Integet对象,之后使用setAttribute来替代老的对象;对于可修改的数据结构,如数组、List、Map或含有实例变量的应用程序专有数据结构,仅当会话中不存在这种对象时才分配对象并调用setAttribute,除非首次分配对象,每个改变对象的内容,会话维护队一个对象的引用。