zl程序教程

您现在的位置是:首页 >  其他

当前栏目

Web项目开发实践,Cookie与Session机制(一)

2023-04-18 14:50:12 时间

会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。本章将系统地讲述Cookie与Session机制,并比较说明什么时候不能用Cookie,什么时候不能用Session。

本章的所有源代码均包含在项目Session中。

5.1 Cookie机制

在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。

而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制。

Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。

5.1.1 什么是Cookie

Cookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。

由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。

查看某个网站颁发的Cookie很简单。在浏览器地址栏输入javascript:alert (document. cookie)就可以了。JavaScript脚本会弹出一个对话框显示本网站颁发的所有Cookie的内容,如图5.1所示。

图5.1 Baidu网站颁发的Cookie

图5.1中弹出的对话框中显示的为Baidu网站的Cookie。其中第一行BAIDUID记录的就是笔者的身份helloweenvsfei,只是Baidu使用特殊的方法将Cookie信息加密了。

%注意:Cookie功能需要浏览器的支持。如果浏览器不支持Cookie(如大部分手机中的浏览器)或者把Cookie禁用了,Cookie功能就会失效。不同的浏览器采用不同的方式保存Cookie。IE浏览器会在“C:Documents and Settings你的用户名Cookies”文件夹下以文本文件形式保存,一个文本文件保存一个Cookie。

5.1.2 记录用户访问次数

Java中把Cookie封装成了javax.servlet.http.Cookie类。每个Cookie都是该Cookie类的对象。服务器通过操作Cookie类对象对客户端Cookie进行操作。通过request.getCookie()获取客户端提交的所有Cookie(以Cookie[]数组形式返回),通过response.addCookie(Cookiecookie)向客户端设置Cookie。

Cookie对象使用key-value属性对的形式保存用户状态,一个Cookie对象保存一个属性对,一个request或者response同时使用多个Cookie。因为Cookie类位于包javax.servlet.http.*下面,所以JSP中不需要import该类。

看一个使用Cookie记录用户账号以及登录次数的例子。在MyEclipse中新建Web Project,选择Java EE 5.0规范,填写项目名称为sessionWeb。新建JSP页面cookie.jsp,输入源代码如下:

代码5.1 cookie.jsp

<%@ page language="java"pageEncoding="UTF-8" errorPage="login.jsp" %>
<%
   request.setCharacterEncoding("UTF-8");             // 设置request编码
    String username ="";                             // 用户名
    int visitTimes = 0;                               // 访问次数
    Cookie[] cookies =request.getCookies();           // 所有的Cookie 
    for(int i=0;cookies!=null&&i<cookies.length; i++){
                                          // 遍历Cookie寻找账号与登录次数
        Cookie cookie =cookies[i];         // 第i个Cookie
       if("username".equals(cookie.getName())){// 如果Cookie名为username
           username = cookie.getValue();       // 则记录该Cookie的内容
        }
        elseif("visitTimes".equals(cookie.getName())){
                                          // 如果Cookie名为visitTimes
           visitTimes = Integer.parseInt(cookie.getValue());
                                          // 则记录Cookie的内容
        }
    }
    if(username == null ||username.trim().equals("")){
                                          // 如果没有找到用户名,则转到登录界面
        throw newException("您还没有登录。请先登录");
    }
    // 修改 Cookie,更新用户的访问次数
    Cookie visitTimesCookie = newCookie("visitTimes", Integer.toString 
    (++visitTimes));
   response.addCookie(visitTimesCookie);   // 覆盖名为visitTimes的Cookie
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">
<html>
<body>
<div style="margin:10px; ">
    <fieldset>
        <legend>登录信息</legend>
        <formaction="login.jsp" method="post">
            <table>
               <tr>
                   <td>您的账号:</td>
                   <td><%= username%></td>
               </tr>
               <tr>
                   <td>登录次数:</td>
                   <td><%= visitTimes%></td>
               </tr>
               <tr>
                   <td></td>
                   <td>
                       <inputtype="button" value=" 刷 新 " onclick= 
                       "location='<%=request.getRequestURI() %>?ts=' + 
                       new Date().getTime(); "class="button">
                   </td>
               </tr>
            </table>
        </form>
    </fieldset>
</div>
</body>
</html>

程序使用Cookie记录用户的访问次数。如果用户没有登录,则显示登录界面。工作原理是程序先检查Cookie,如果没有找到包含username属性的Cookie,则抛出异常,页面跳转到errorPage指定的错误处理页面login.jsp。login.jsp源代码如下:

代码5.2 login.jsp

<%@ page language="java"pageEncoding="UTF-8" isErrorPage="true" %>
<%
   request.setCharacterEncoding("UTF-8");      // 设置request编码方式
   response.setCharacterEncoding("UTF-8"); // 设置response编码方式
   if("POST".equals(request.getMethod())){ // 如果是以POST方式登录
        CookieusernameCookie =                // 新建名为username的Cookie
        newCookie("username", request.getParameter("username"));
        CookievisittimesCookie = new Cookie("visitTimes", "0");
                                              // 新建Cookie
       response.addCookie(usernameCookie); // 添加到response中
       response.addCookie(visittimesCookie);   // response会将Cookie发送
 给客户端
       response.sendRedirect(request.getContextPath() +"/cookie.jsp");    // 显示Cookie页面
        return;
    }
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">
<html>
<head>
<title>请先登录</title>
<link rel="stylesheet"type="text/css" href="css/style.css">
</head>
<body>
<div style="margin:10px;">
    <fieldset>
        <legend>登录</legend>
        <formaction="login.jsp" method="post">
           <table>
               <tr>
                   <td></td>
                   <td><span><imgsrc="images/errorstate.gif"></span>
                       <spanstyle="color:red; "><%= exception.get 
                       Message() %></span></td>
               </tr>
               <tr>
                   <td>账号: </td>
                   <td><input type="text"name="username" style="width: 
                   200px; "></td>
               </tr>
               <tr>
                   <td>密码: </td>
                   <td><inputtype="password" name="password" style= 
                   "width:200px; "></td>
               </tr>
               <tr>
                   <td></td>
                   <td><inputtype="submit" value=" 登 录 " class= 
                   "button"></td>
               </tr>
           </table>
        </form>
    </fieldset>
</div>
</body>
</html>

程序运行效果如图5.2所示。

图5.2 使用Cookie记录用户访问次数

客户端A与客户端B都可能访问该程序,A会提交A的Cookie,B会提交B的Cookie。代码request.getCookies()并没有指明获取谁的Cookie。这句代码取的是谁的Cookie呢?答案是A执行时取的是A的Cookie,B执行时取的是B的Cookie。这是Cookie机制规定的。程序只需要简单执行request.getCookies()就可以了,服务器只会返回当前客户的Cookie,而不会返回其他客户的Cookie。各客户端的Cookie彼此独立,互不可见。