学习目标

  • 了解Cookie的基本概念
  • 掌握在JSP中创建Cookie的方法
  • 掌握在JSP中读写Cookie的方法
  • 掌握设置Cookie存在期限的方法
  • 了解Cookie的安全问题

目录:

在Web开发中,Http连接无状态

Cookie的概念和特性

Cookie是设计交互式网页的一项重要技术,它可以将一些简短的数据存储在用户的计算机上,这些存放在用户计算机上的变量数据,称为Cookie。当浏览器向服务器提出网页浏览请求时,服务器根据存储在用户计算机上面的Cookie内容,针对此浏览器显示其专门的内容。

什么是Cookie

Cookie是一个存储在浏览器目录的文本文件,当浏览器运行时,存储在RAM(随机存储内存)中。一旦用户从该网站或网络服务器退出,Cookie也可存储在计算机的硬驱上。当访客结束其浏览器对话时,即终止所有的Cookie。Cookie是在HTTP协议下,服务器或脚本可以维护客户工作站上信息的一种方式。

有些Cookie是临时的,有些则是持续的。临时的Cookie只在浏览器上保存一段规定的时间,一旦超过规定的时间,该Cookie就会被系统清除。持续的Cookie则保存在用户的Cookie文件中,下一次用户返回时,仍然可以对它进行调用。

Cookie必须在HTML文件的内容输出之前设置;不同的浏览器对Cookie的处理不一致;客户端用户如果设置禁止Cookie,则Cookie不能建立。一个浏览器能创建的Cookie数量最多为300个,并且每个不能超过4KB,每个Web站点能设置的Cookie总数不能超过20个。

Cookie是服务器发送给浏览器的体积非常小的纯文本信息,用户以后访问同一个Web服务器时浏览器会把他们原样发送给服务器。通过让服务器读取他原先保存到客户端的信息,网站能够为浏览者提供一系列的方便,例如在线交易过程中标识用户身份、安全需求不高的场合避免用户重复输入名字和密码、门户网站的主页制定、有针对性地投放广告,等等。

Cookie数据存储的功能由浏览器本身所提供,因此Cookie功能都必须要有浏览器的支持才行,一般通用的浏览器,例如IE都支持此功能。

当用户打开的网页中包含Cookie程序代码,此时服务器端会建立Cookie数据,然后将这个Cookie传送到客户端用户的计算机上。

5-1-1.png

当Cookie的数据传送至客户端的计算机后,便存储在浏览器中,此时服务器端的网页都可以访问这个Cookie的数据内容,而当用户关闭浏览器的时候,Cookie的数据便会消失。

若服务器在建立Cookie时设置了Cookie的存在时间期限,则用户在关闭浏览器后,Cookie的数据会以文本文件存储在用户的计算机上,只要在设置的时间期限内,当用户连接网页时,服务器端的网页均可使用先前Cookie的内容,等过了所设置的期限,Cookie中的数据便会自动被删除。

Cookie的常见用途

Cookie最根本的用途是帮助Web站点保存有关访问者的信息,是一种保持Web应用程序连续性(即执行“状态管理”)的方法。浏览器和Web服务器除了在短暂的实际信息交换阶段以外总是断开的,而用户向Web服务器发送的每个请求都是单独处理的,与其他所有请求无关。然而在大多数情况下,都有必要让Web服务器在用户请求某个页面时对其进行识别。

Cookie的作用就类似与名片,它提供了相关的标识信息,可以帮助应用程序确定如何继续执行。

Cookie的常见用途如:

  • 网站浏览人数管理
  • 按照用户的喜好定制网页外观
  • 在电子商务站点中实现诸如“购物篮”等功能

Cookies给网站和用户带来的好处非常多:

  • Cookie能使站点跟踪特定访问者的访问次数、最后访问时间和访问者进入站点的路径。
  • Cookie能告诉在线广告商广告被点击的次数 ,从而可以更精确的投放广告。
  • Cookie有效期限未到时,Cookie能使用户在不键入密码和用户名的情况下进入曾经浏览过的一些站点。
  • Cookie能帮助站点统计用户个人资料以实现各种各样的个性化服务。

Cookie的安全问题

  • Cookie欺骗
  • Flash的代码隐患
  • 隐私,安全和广告
  • 偷窃Cookie和脚本攻击
  • 网站以外的用户无法跨过网站来获得Cookie信息。

在JSP中使用Cookie

Cookie实质是服务器端与客户端之间传送的普通HTTP头,可以保存也可以不保存在客户的硬盘上。如果保存,是每个文件大小不超过4KB的文本文件,多个Cookie可保存到同一个文件中。从编程角度来看,在JSP中,Cookie就是Java提供的一个类。

response对象与request对象均提供与Cookie相关的方法成员,利用这些成员,用户可以很方便地访问指定的Cookie内容。

创建Cookie

Cookie是由Javax.servlet.http.Cookie类所衍生出来的对象,建立Cookie的语法如下:
Cookie objCookie = new Cookie(indexValue,stringValue)

从上面的语法中可以看出,一个Cookie对象必须包含有一个特定的indexValue索引值字符串类型的数据内容stringValue。例如:

<% Cookie c = new Cookie("mycookie","Cookie Test"); %>

建立了Cookie之后,该Cookie数据还必须传送到客户端,用addCookie()方法发送一个HTTP Header。传送的方式为:response.addCookie(objCookie)

读写Cookie

  1. 写Cookie

对Cookie进行操作首先是将Cookie保存到客户端。在JSP中,利用response对象,通过addCookie()方法将Cookie写入客户端。其语法格式如下:response.addCookie(cookie);

例如:

   <% // 从提交的HTML表单中获取用户名
    String username=request.getParameter(name);
    Cookie user_name=new Cookie("cookie_name",username);
    // 创建一个Cookie
    response.addCookie(user_name);
   %>
  1. 读Cookie

将Cookie保存到客户端,就是为了以后得到其中保存的数据。调用HttpServletRequestgetCookies得到一个Cookie对象的数组。其语法格式如下:
Cookie[] 数组变量名=request.getCookies();

在客户端传来的Cookie数据类型都是数组类型,因此要得到其中某一项指定的Cookie对象,需要遍历数组来找。JSP将调用request.getCookies()从客户端读入Cookie,getCookies()方法返回一个HTTP请求头中的内容对应的Cookie对象数组。用户只需要用循环访问该数组的各个元素,调用getName()方法检查各个Cookie的名字,直至找到目标Cookie,然后对该Cookie调用getValue()方法取得与指定名字关联的值,可通过如下代码实现:

<%
   Cookie[] Cookies=request.getCookies(); // 创建一个Cookie对象数组
   if(Cookies == null)
      out.print("none any Cookie ");
   else {
    for (int i=0;i< Cookies.length;i++) {
        // 设立一个循环,来访问Cookie对象数组的每一个元素
        if(Cookies[i].getName().equals("cookie_name")) 
            // 判断元素的值是否为username中的值
            out.println(Cookies[i].getValue()+"<br>");
    }
   }
%>

操作Cookie的常用方法

  1. 设置Cookie的存在期限

Cookie可以保持登录信息到用户下次与服务器会话,换句话说,下次访问同一网站时,用户会发现不必输入用户名和密码就已经登录了。而还有一些Cookie在用户退出会话时就被删除了。

Cookie在生成时就会被指定一个Expire值,这就是Cookie的生存周期,在这个周期内Cookie有效,超出周期Cookie就会被清除。有些页面将Cookie的生存周期设置为0或负值,这样在关闭页面时,就马上清除Cookie,不会记录用户信息,更加安全。在默认情况下,Cookie是随着用户关闭浏览器而自动消失的,不过,Cookie也可以设置其存在的期限,让用户下次在打开网页时,服务器端仍然能够取得同样一个Cookie中的数据内容。

设置Cookie变量的有效周期的语法如下:Cookie 名称.setMaxAge(有效周期);

有效周期的时间以秒为单位,时间设置越大,表示Cookie对象的有效时间越长。

<%
    Cookie cookie = new Cookie(“username”,”liuyongpo”);
    cookie.setMaxAge(30 * 60); // 设置Cookie的存活时间为30分钟
    response.addCookie(cookie);
%>

自动保存的Cookie

package ch06;
import javax.servlet.http.*;
public class LongLivedCookie extends Cookie { 
    public static final int SECONDS_PER_YEAR = 60*60*24*365;
    public LongLivedCookie(String name, String value) { 
        super(name, value);                                           
        setMaxAge(SECONDS_PER_YEAR);                                    
    } 
}
  1. 删除Cookie

要删除一个Cookie,必须使用sexMaxAge()方法,并将Cookie的存在期限设为0,语法如下:

Cookie 名称.setMaxAge(0);

例如:

<%
     Cookie killMyCookie = new Cookie("mycookie", null); 
     killMyCookie.setMaxAge(0); 
     killMyCookie.setPath("/"); 
     response.addCookie(killMyCookie);
%>
  1. 获取指定名字的Cookie值

下面的代码可以获取指定名字的Cookie值:

public static String getCookieValue(Cookie[] cookies, 
        String cookieName, String defaultValue) { 
    for(int i=0; i<cookies.length; i++) { 
            Cookie cookie = cookies[i]; 
        if (cookieName.equals(cookie.getName()))
            return(cookie.getValue()); 
    } 
        return(defaultValue); 
}

Cookie对象的应用实例

  • 从结果可见,同一台机器的不同客户端访问都可以访问服务器保存在本地机器的Cookie。新开启的页面中未保存JSESSIONID的信息。

  • JSESSIONID就是客户端用来保存sessionid的变量,一般对于Web应用来说,客户端变量都会保存在Cookie中,JSESSIONID也不例外。不过与一般的Cookie变量不同,JSESSIONID是保存在内存Cookie中的,在一般的Cookie文件中看不到。内存Cookie在打开一个浏览器窗口的时候会创建,在关闭这个浏览器窗口的时候也同时销毁。所以session变量不能跨窗口使用,要跨窗口使用就需要手动把JSESSIONID保存到Cookie里面。

  • 只有通过JSESSIONID才能使session机制起作用,而JSESSIONID又是通过Cookie来保存的。如果用户禁用了Cookie,可以通过URL重写来实现JSESSIONID的传递。JSESSIONID通过这样的方式从客户端传递到服务器端,从而标识session。这样在用户禁用Cookie的时候也可以传递JSESSIONID来使用session,只不过需要每次都把JSESSIONID作为参数跟在URL后面传递。

  • response.encodeURL()response.encodeRedirectURL()方法。

    这两个方法会判断Cookie是否可用,如果禁用了会解析出URL中的JSESSIONID,并连接到指定的URL后面,如果没有找到JSESSIONID会自动生成一个。这两个方法在判断是否要包含JSESSIONID的逻辑上会稍有不同。在调用response.sendRedirect()之前,应该先调用response.encodeURL()response.encodeRedirectURL()方法,否则可能会丢失session信息。

会话与会话追踪

session,中文经常翻译为“会话”,其本来的含义是指有始有终的一系列动作或消息,比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。

“会话”本义是指从一个浏览器窗口打开到关闭这个期间。

session的含义很多,session tracking(会话追踪)是指一类用来在客户端与服务器之间保持状态的解决方案,简单地说,当一个客户在多个页面间切换时,服务器会保存该用户的信息。

购物车的可能实现方式有哪些? (==ABCD==)
A. cookie B.session C.appliaction D.Database

实现会话追踪的4种方式

会话追踪的实现方式有下列4种方式:

  1. 使用持续Cookies(Persistent Cookies)
  2. 重写包含额外参数的URL(URL Rewriting)
  3. 建立含有数据的隐藏表单字段(Hidden Form Field)
  4. 使用内建session对象

使用内建session对象是目前最常用,也最有效的解决方案。

Cookies和URL重写

Cookie是一个小小的文本文件,它是将会话信息记录在这个文本文件内,每个页面都去Cookie中提取以前的会话信息。用户请求到达服务器后,先从Cookie中取出会话信息,这样就实现了会话追踪。

虽然Cookie强大且持续性高,但是由于有些用户因为担心Cookie对个人隐私的威胁,会关闭Cookie,一旦如此,便无法利用Cookie来达到会话追踪的功能。

URL重写是利用get方法,在URL的尾部添加一些额外的参数来达到会话追踪(session tracking)的目的,服务器将这个标识符与它所存储的有关会话的数据关联起来。URL后面用;来分隔JSESSIONID

使用URL重写的优点是Cookie被禁用或者根本不支持的情况下依旧能够工作。但也有很多缺点:

  • 必须对所有指向某用户的网站的URL进行编码
  • 所有页面必须动态生成
  • 不能使用预先记录下来的URL进行访问,或者从其他网站链接进行访问

隐藏表单字段

隐藏表单字段的方法,是利用HTML内的Hidden属性,把客户端的信息,在用户不察觉的情形下,偷偷地随着请求一起传送给服务器处理,从而实现会话跟踪的任务。然后将重要的用户信息,以隐藏字段的方式传送给服务器。

优点:session数据传送到服务器端时,并不像get方法会将session数据暴露在URL之上。
缺点:一旦session数据存储在隐藏字段中,仍然可以在用户直接查看HTML源文件的时候暴露数据。

使用内建session对象

传统的会话追踪方式使用比较麻烦,JSP使用内建的session对象可以非常方便地实现会话追踪,JSP的会话机制基于Cookie或URL重写技术,融合了这两种技术的优点,当客户端允许使用Cookie时,内建session对象使用Cookie进行会话追踪,如果客户端禁用Cookie,则选择使用URL重写。

  1. 获取session对象。例如把购物车作为属性存储在session中,在其他JSP页面中可以通过session再获得购物车。
<%
   // 在JSP页面中可以直接使用session
   ShoppingCart cart = (ShoppingCart)session.getAttribute("cart");
%>

内建的session对象是javax.servlet.http.HttpSession类的实例,如果在JavaBean或者Servlet中使用session就需要先从当前的request对象中取得,例如:

   <%
   // 得到用户session和购物车
   HttpSession session = request.getSession();
   ShoppingCart cart = (ShoppingCart)session.getAttribute("cart");
   %>
  1. 读写session中的数据。向session中存入对象使用setAttribute方法,通过getAttribute方法读取对象。从session返回的值注意要转换成合适的类型,要注意检查结果是否为null。例如下面一段代码:
    HttpSession session=request.getSession();
    SomeClass value=(SomeClass)session.getAttribute("someID");
    if(value==null) {
     value=new SomeClass(…);
     session.setAttribute("someID",value);
    }
  1. 废弃session数据。调用removeAttribute废弃session中的值,即移除与名称关联的值。调用invalidate废弃整个session,即废弃当前的session。如果用户注销离开站点,注意废弃与用户相关联的所有session。

  2. session的生命周期。由于没有办法知道HTTP客户端是否不再需要session,因此每个session都关联一个时间期限使它的资源可以被回收。

  3. 服务器使用URL重写。session默认使用Cookie技术进行会话追踪,如果客户端不接受Cookie的时候,服务器可以利用URL重写的方式将sessionID作为参数附在URL后面,此时须利用response对象内的encodeURLencodeRedirectURL方法,这两个方法首先判断Cookies是否被浏览器支持;如果支持,则参数URL被原样返回,sessionID将通过Cookies来维持。否则返回带有sessionID的URL。同时需要注意的是,将session的ID以URL的编码方式进行时,需将每一页都编码,才能保留住session的ID。如果遇到没有编码的URL,则无法进行会话跟踪。

  4. 内建session对象使用示例。下面是一个记录同一用户到站次数的计数器:

   <%@ page contentType="text/html;charset=gb2312"%>
   <html>
   <title>session记录光临本页面的次数</title>
   <body>
   <%
   String heading = null;
   Integer accessCount = (Integer) session.getAttribute("accessCount");
   if (accessCount == null) {
    accessCount = new Integer(0);
    heading = "Welcome, Newcomer";
    } else {
        heading = "Welcome Back";
        accessCount = new Integer(accessCount.intValue() + 1);
       }
    session.setAttribute("accessCount", accessCount);
   %>
   <H1> <% out.println(heading); %> </H1>
   <H2>以前进入页面次数: <% out.println(accessCount); %> </H2>
   </body>
   </html>

内建session对象的生命周期

内建session对象和Cookie一样拥有特定的生命周期。一般来说,内建session对象在一段时间没有作用就会自动失效,也就是服务器会自动控管session的失效时间。除此之外,也可以利用HttpSession类的setMaxInactiveInterval()方法来设定内建session对象的过期时间,服务器就会将session的资源释放掉。另外也可以使用HttpSession类的invalidate()方法,session不论设定多久的时间为过期,都将立即消失。

在web.xml中配置内建session对象的过期时间

session在一段时间没有作用就会自动失效,也就是服务器会自动管控session失效的时间,不过时间的长短通常因JSP容器所设定session失效的时间各有所不同,但是当设计者有特别需求时,也可以手动设定session过期时间。以tomcat为例,用户可以在web.xml中配置内建session对象的过期时间为30分钟。

<web-app>
…
<session-config>
    <session-timeout>30</session-timeout>
</session-config>
…
</web-app>

设置内建session对象的过期时间

在服务器上,通过为在站点上的用户创建一个内建session对象保存该用户的信息。当用户第一次访问站点时,分配给用户一个session对象和一个单独的会话ID,这个ID是唯一的。在接下来的请求中,会话ID标识了这个用户,session对象作为请求的一部分发送给Servlet,Servlet能从session对象中读取信息,或者为其添加信息。

一个session可以利用isNew()方法来得知是否为一个新的session。所谓“新”的session,意思是说:它已被服务器产生,但是客户端尚未被告知。

由于没有办法知道HTTP客户端是否不再需要session,因此每个session都关联一个时间期限使它的资源可以被回收。setMaxInactiveInterval()和getMaxInactiveInterval()方法访问超时时间。当客户端完成一个(组)完整的交互过程后,可以使用invalidate()方法使服务器端的session失效,并清除session数据。

<%@ page contentType="text/html;charset=gb2312"%>
<html>
<title>session的生命周期</title>
<body>
<%  //如果session是新的,设定session的初值
if (session.isNew()) {
    //设置session若十秒内没有活动则使session过期
    session.setMaxInactiveInterval(10);
    //将此session time out的秒数加入过期时间中
    session.setAttribute("expire", "10");%>     
<H1> <%out.print("session生命周期示例");%> </H1>
<%  out.print("设定session若十秒钟没有活动则使session过期"+session.getId());}
else{
    String str_expire_time=(String)session.getAttribute("expire");
    //取得session构建的时间
    long create_time=session.getCreationTime();
    long access_time=session.getLastAccessedTime(); 
    long current_time=System.currentTimeMillis();
    long exist_time=(current_time-create_time)/1000;
    out.print("session已存在"+exist_time+"秒");
    //如果session存在的时间超过20秒,则删除session
    if(exist_time>=20){
        out.print("session时间已到...自动失效");
        session.invalidate();
    }
}
%>
</body>
</html>

在web.xml中,<session-timeout>30 </session-timeout>的单位是分钟,session.setMaxInactiveInterval(10)的单位是秒。