理解Cookie和Session机制

in TCEH with 0 comment

一、Cookie

1、Cookie简介

  会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。

  Cookie技术是客户端的解决方案,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。让我们说得更具体一些:当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器;接着,服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在HTTP响应体(Response Body)中的,而是存放于HTTP响应头(Response Header);当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置,对于Windows操作系统而言,我们可以从浏览器设定缓存目录中找到存储的Cookie;自此,客户端再向服务器发送请求的时候,都会把相应的Cookie再次发回至服务器。而这次,Cookie信息则存放在HTTP请求头(Request Header)了。有了Cookie这样的技术实现,服务器在接收到来自客户端浏览器的请求之后,就能够通过分析存放于请求头的Cookie得到客户端特有的信息,从而动态生成与该客户端相对应的内容。通常,我们可以从很多网站的登录界面中看到“请记住我”这样的选项,如果你勾选了它之后再登录,那么在下一次访问该网站的时候就不需要进行重复而繁琐的登录动作了,而这个功能就是通过Cookie实现的。

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

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

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

  如果你把Cookies看成为http协议的一个扩展的话,理解起来就容易的多了,其实本质上cookies就是http的一个扩展。有两个http头部是专门负责设置以及发送cookie的,它们分别是Set-Cookie以及Cookie。当服务器返回给客户端一个http响应信息时,其中如果包含Set-Cookie这个头部时,意思就是指示客户端建立一个cookie,并且在后续的http请求中自动发送这个cookie到服务器端,直到这个cookie过期。如果cookie的生存时间是整个会话期间的话,那么浏览器会将cookie保存在内存中,浏览器关闭时就会自动清除这个cookie。另外一种情况就是保存在客户端的硬盘中,浏览器关闭的话,该cookie也不会被清除,下次打开浏览器访问对应网站时,这个cookie就会自动再次发送到服务器端。

  一个cookie的设置以及发送过程分为以下四步:

1、客户端发送一个http请求到服务器端

2、服务器端发送一个http响应到客户端,其中包含Set-Cookie头部

3、客户端发送一个http请求到服务器端,其中包含Cookie头部

4、服务器端发送一个http响应到客户端

  在客户端的第二次请求中包含的Cookie头部中,提供给了服务器端可以用来唯一标识客户端身份的信息。这时,服务器端也就可以判断客户端是否启用了cookies。尽管,用户可能在和应用程序交互的过程中突然禁用cookies的使用,但是,这个情况基本是不太可能发生的,所以可以不加以考虑,这在实践中也被证明是对的。

  除了cookies,客户端还可以将发送给服务器的数据包含在请求的url中,比如请求的参数或者请求的路径中。 我们来看一个常规的http get 请求例子:

GET /index.jsp?foo=bar HTTP/1.1 Host: example.org
  另外一种客户端传递数据到服务器端的方式是将数据包含在http请求的内容区域内。 这种方式需要请求的类型是POST的,看下面一个例子:
POST /index.jsp HTTP/1.1 Host: example.org Content-Type: application/x-www-form-urlencoded Content-Length: 7

foo=bar

在一个请求中,可以同时包含这两种形式的数据:

POST /index.jsp?myget=foo HTTP/1.1 Host: example.orgContent-Type: application/x-www-form-urlencoded Content-Length: 11

mypost=bar
  这两种传递数据的方式,比起用cookies来传递数据更稳定,因为cookie可能被禁用,但是以GET以及POST方式传递数据时,不存在这种情况。我们可以将JSESSIONID包含在http请求的url中,就像下面的例子一样:

GET /index.jsp?JSESSIONID=12345 HTTP/1.1 Host: example.org

2、Cookie的不可跨域名性

  很多网站都会使用Cookie。例如,Google会向客户端颁发Cookie,Baidu也会向客户端颁发Cookie。那浏览器访问Google会不会也携带上Baidu颁发的Cookie呢?或者Google能不能修改Baidu颁发的Cookie呢?

  答案是否定的。Cookie具有不可跨域名性。根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。Google也只能操作Google的Cookie,而不能操作Baidu的Cookie。

  Cookie在客户端是由浏览器来管理的。浏览器能够保证Google只会操作Google的Cookie而不会操作Baidu的Cookie,从而保证用户的隐私安全。浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。Google与Baidu的域名不一样,因此Google不能操作Baidu的Cookie。

  需要注意的是,虽然网站images.google.com与网站www.google.com同属于Google,但是域名不一样,二者同样不能互相操作彼此的Cookie。

  注意:用户登录网站www.google.com之后会发现访问images.google.com时登录信息仍然有效,而普通的Cookie是做不到的。这是因为Google做了特殊处理。本章后面也会对Cookie做类似的处理。

3、设置Cookie的所有属性

String name

  该Cookie的名称。Cookie一旦创建,名称便不可更改。

Object value

  该Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码。

int maxAge

  该Cookie失效的时间,单位秒。如果为正数,则该Cookie在maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1。

boolean secure

  该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。

String path

  该Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”。

String domain

  可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”。

String comment

  该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明。

int version

  该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范。

boolean httpOnly

  该属性增强安全,避免一定程度的跨站攻击。

4、Java使用的简单示例

        Cookie cookie = new Cookie("jsonp", cool);
        cookie.setMaxAge(Integer.MAX_VALUE);
        cookie.setComment("comment");
        cookie.setDomain("wjx.wiki");
        cookie.setHttpOnly(true);
        cookie.setPath("/tceh/");
        cookie.setSecure(true);
        cookie.setVersion(0);
        resp.addCookie(cookie);

5、完整案例:用户登录

  如果用户是在自己家的电脑上上网,登录时就可以记住他的登录信息,下次访问时不需要再次登录,直接访问即可。实现方法是把登录信息如账号、密码等保存在Cookie中,并控制Cookie的有效期,下次访问时再验证Cookie中的登录信息即可。

  保存登录信息有多种方案。最直接的是把用户名与密码都保持到Cookie中,下次访问时检查Cookie中的用户名与密码,与数据库比较。这是一种比较危险的选择,一般不把密码等重要信息保存到Cookie中。

  还有一种方案是把密码加密后保存到Cookie中,下次访问时解密并与数据库比较。这种方案略微安全一些。如果不希望保存密码,还可以把登录的时间戳保存到Cookie与数据库中,到时只验证用户名与登录时间戳就可以了。

这几种方案验证账号时都要查询数据库。

  本例将采用另一种方案,只在登录时查询一次数据库,以后访问验证登录信息时不再查询数据库。实现方式是把账号按照一定的规则加密后,连同账号一块保存到Cookie中。下次访问时只需要判断账号的加密规则是否正确即可。本例把账号保存到名为account的Cookie中,把账号连同密钥用MD5算法加密后保存到名为ssid的Cookie中。验证时验证Cookie中的账号与密钥加密后是否与Cookie中的ssid相等。相关代码如下: loginCookie.jsp:

<%@page import="java.security.MessageDigest"%>
<%@ page language="java" pageEncoding="UTF-8" isErrorPage="false"%>
<%!// JSP方法
    private static final String KEY = ":cookie@helloweenvsfei.com"; // 密钥 

    public static String md5Encode(String inputStr, String charsetName) throws Exception {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        byte[] byteArray = inputStr.getBytes(charsetName);
        byte[] md5Bytes = md5.digest(byteArray);

        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }%>
<%
    request.setCharacterEncoding("UTF-8"); // 设置request编码
    response.setCharacterEncoding("UTF-8"); // 设置response编码
    String action = request.getParameter("action"); // 获取action参数
    String charsetName = "UTF-8";

    if ("login".equals(action)) { // 如果为login动作
        String account = request.getParameter("account"); // 获取account参数
        String password = request.getParameter("password"); // 获取password参数
        int timeout = new Integer(request.getParameter("timeout")); // 获取timeout参数

        String ssid = md5Encode(account + KEY, charsetName); // 把账号、密钥使用MD5加密后保存

        Cookie accountCookie = new Cookie("account", account); // 新建Cookie
        accountCookie.setMaxAge(timeout); // 设置有效期

        Cookie ssidCookie = new Cookie("ssid", ssid); // 新建Cookie
        ssidCookie.setMaxAge(timeout); // 设置有效期

        response.addCookie(accountCookie); // 输出到客户端
        response.addCookie(ssidCookie); // 输出到客户端

        // 重新请求本页面,参数中带有时间戳,禁止浏览器缓存页面内容
        response.sendRedirect(request.getRequestURI() + "?" + System.currentTimeMillis());
        return;
    } else if ("logout".equals(action)) { // 如果为logout动作
        Cookie accountCookie = new Cookie("account", ""); // 新建Cookie,内容为空
        accountCookie.setMaxAge(0); // 设置有效期为0,删除

        Cookie ssidCookie = new Cookie("ssid", ""); // 新建Cookie,内容为空
        ssidCookie.setMaxAge(0); // 设置有效期为0,删除
        response.addCookie(accountCookie); // 输出到客户端
        response.addCookie(ssidCookie); // 输出到客户端
        // 重新请求本页面,参数中带有时间戳,禁止浏览器缓存页面内容
        response.sendRedirect(request.getRequestURI() + "?" + System.currentTimeMillis());
        return;
    }
    boolean login = false; // 是否登录
    String account = null; // 账号
    String ssid = null; // SSID标识

    if (request.getCookies() != null) { // 如果Cookie不为空
        for (Cookie cookie : request.getCookies()) { // 遍历Cookie
            if (cookie.getName().equals("account")) // 如果Cookie名为 account
                account = cookie.getValue(); // 保存account内容
            if (cookie.getName().equals("ssid")) // 如果为SSID
                ssid = cookie.getValue(); // 保存SSID内容
        }
    }
    if (account != null && ssid != null) { // 如果account、SSID都不为空
        login = ssid.equals(md5Encode(account + KEY, charsetName)); // 如果加密规则正确, 则视为已经登录
    }
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">
<legend><%=login ? "欢迎您回来" : "请先登录"%></legend>
<%
    if (login) {
%>
欢迎您, ${cookie.account.value }. &nbsp;&nbsp;
<a href="${pageContext.request.requestURI }?action=logout"> 注销</a>
<%
    } else {
%>
<form action="${ pageContext.request.requestURI }?action=login"
    method="post">
    <table>
        <tr>
            <td>账号:</td>
            <td><input type="text" name="account" style="width: 200px;"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td>有效期:</td>
            <td>
            <input type="radio" name="timeout" value="-1" checked>关闭浏览器即失效 <br /> 
            <input type="radio" name="timeout" value="10" >10秒钟内有效 <br /> 
            <input type="radio" name="timeout" value="<%=30 * 24 * 60 * 60%>"> 30天 内有效 <br />
            <input type="radio" name="timeout" value="<%=Integer.MAX_VALUE%>"> 永久有效 <br /></td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit" value=" 登  录 " class="button"></td>
        </tr>
    </table>
</form>
<%
    }
%>

二、Session

1、Session简介

  Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

  如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要通过客户号来查询客户档案表就可以了。

2、实现用户登录

  Session对应的类为javax.servlet.http.HttpSession类。每个来访者对应一个Session对象,所有该客户的状态信息都保存在这个Session对象里。Session对象是在客户端第一次请求服务器的时候创建的。Session也是一种key-value的属性对,通过getAttribute(Stringkey)和setAttribute(String key,Object value)方法读写客户状态信息。Servlet里通过request.getSession()方法获取该客户的Session,例如:


        HttpSession session = req.getSession();       // 获取Session对象
        session.setAttribute("loginTime", new Date());     // 设置Session中的属性
        System.out.println("登录时间为:" +(Date)session.getAttribute("loginTime"));      // 获取Session属性

  request还可以使用getSession(boolean create)来获取Session。区别是如果该客户的Session不存在,request.getSession()方法会返回null,而getSession(true)会先创建Session再将Session返回。
  使用起来要比Cookie方便。当多个客户端执行程序时,服务器会保存多个客户端的Session。获取Session的时候也不需要声明获取谁的Session。Session机制决定了当前客户只会获取到自己的Session,而不会获取到别人的Session。各客户的Session也彼此独立,互不可见。

  一个完整且简单基于Session的用户登录示例 点我访问

提示:Session的使用比Cookie方便,但是过多的Session存储在服务器内存中,会对服务器造成压力。

3、Session的生命周期

  Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。

  Session在用户第一次访问服务器的时候自动创建。需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。如果尚未生成Session,也可以使用request.getSession(true)强制生成Session。

  Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。

4、Session的有效期

  由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。

  Session的超时时间为maxInactiveInterval属性,可以通过对应的getMaxInactiveInterval()获取,通过setMaxInactiveInterval(longinterval)修改。

  Session的超时时间也可以在web.xml中修改。另外,通过调用Session的invalidate()方法可以使Session失效。

5、Session的常用方法

void setAttribute(String attribute, Object value)

  设置Session属性。value参数可以为任何Java Object。通常为Java Bean。value信息不宜过大

String getAttribute(String attribute)

  返回Session属性

Enumeration getAttributeNames()

  返回Session中存在的属性名

void removeAttribute(String attribute)

  移除Session属性

String getId()

  返回Session的ID。该ID由服务器自动创建,不会重复

long getCreationTime()

  返回Session的创建日期。返回类型为long,常被转化为Date类型,例如:Date createTime = new Date(session.getCreationTime())

long getLastAccessedTime()

  返回Session的最后活跃时间。返回类型为long

int getMaxInactiveInterval()

  返回Session的超时时间。单位为秒。超过该时间没有访问,服务器认为该Session失效

void setMaxInactiveInterval(int second)

  设置Session的超时时间。单位为秒

boolean isNew()

  返回该Session是否是新创建的

void invalidate()

  使该Session失效

Tomcat中Session的默认超时时间为20分钟。通过setMaxInactiveInterval(int seconds)修改超时时间。可以修改web.xml改变Session的默认超时时间。例如修改为60分钟

<session-config>
   <session-timeout>60</session-timeout>      <!-- 单位:分钟 -->
</session-config>

注意:参数的单位为分钟,而setMaxInactiveInterval(int s)单位为秒。

在server.xml中定义context时采用如下定义(单位为秒):

<Context path="/livsorder" docBase="/home/httpd/html/livsorder" defaultSessionTimeOut="3600" isWARExpanded="true"
    isWARValidated="false" isInvokerEnabled="true"
    isWorkDirPersistent="false"/>

6、Session对浏览器的要求

  虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为Session需要使用Cookie作为识别标志。HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。

该Cookie为服务器自动生成的,它的maxAge属性一般为–1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。

  因此同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。但是由浏览器窗口内的链接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的Cookie,因此会共享一个Session。

注意:新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。例如,在链接上右击,在弹出的快捷菜单中选择“在新窗口中打开”时,子窗口便可以访问父窗口的Session。

如果客户端浏览器将Cookie功能禁用,或者不支持Cookie怎么办?例如,绝大多数的手机浏览器都不支持Cookie。Java Web提供了另一种解决方案:URL地址重写。

URL地址重写

  URL地址重写是对客户端不支持Cookie的解决方案。URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。HttpServletResponse类提供了encodeURL(Stringurl)实现URL地址重写,例如:

<td>
    <a href="<%=response.encodeURL("index.jsp?c=1&wd=Java") %>"> 
    Homepage</a>
</td>

该方法会自动判断客户端是否支持Cookie。如果客户端支持Cookie,会将URL原封不动地输出来。如果客户端不支持Cookie,则会将用户Session的id重写到URL中。重写后的输出可能是这样的:

<td>
    <a href="index.jsp;jsessionid=0CCD096E7F8D97B0BE608AFDC3E1931E?c=1&wd=Java">Homepage</a>
</td>

  即在文件名的后面,在URL参数的前面添加了字符串“;jsessionid=XXX”。其中XXX为Session的id。分析一下可以知道,增添的jsessionid字符串既不会影响请求的文件名,也不会影响提交的地址栏参数。用户单击这个链接的时候会把Session的id通过URL提交到服务器上,服务器通过解析URL地址获得Session的id。

如果是页面重定向(Redirection),URL地址重写可以这样写:

<%
    if(“administrator”.equals(userName)) {
        response.sendRedirect(response.encodeRedirectURL(“administrator.jsp”));
        return;
    }
%>

  效果跟response.encodeURL(String url)是一样的:如果客户端支持Cookie,生成原URL地址,如果不支持Cookie,传回重写后的带有jsessionid字符串的地址。

  由于Cookie可以被人为的禁止,必须有其他机制以便在Cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面,附加方式也有两种: 一种是作为URL路径的附加信息,表现形式为http://...../xxx;jsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764 一种是作为查询字符串附加在URL后面,表现形式为http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764

  这两种方式对于用户来说是没有区别的,只是服务器在解析的时候处理的方式不同,采用第一种方式也有利于把session id的信息和正常程序参数区分开来。为了在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。

表单隐藏字段

  就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如下面的表单:

<form name="testform" action="/xxx">
    <input type="text">
</form>
在被传递给客户端之前将被改写成:

<form name="testform" action="/xxx">
    <input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
    <input type="text">
</form>

这种技术现在已较少应用。

  在谈论session机制的时候,常常听到这样一种误解“只要关闭浏览器,session就消失了”。其实可以想象一下会员卡的例子,除非顾客主动对店家提出销卡,否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的,除非程序通知服务器删除一个session,否则服务器会一直保留,程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭,因此服务器根本不会有机会知道浏览器已经关闭,之所以会有这种错觉,是大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个 session id就消失了,再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求头,把原来的session id发送给服务器,则再次打开浏览器仍然能够找到原来的session。

  恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为session设置了一个失效时间,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。

7、Session中禁止使用Cookie

  既然WAP上大部分的客户浏览器都不支持Cookie,索性禁止Session使用Cookie,统一使用URL地址重写会更好一些。Java Web规范支持通过配置的方式禁用Cookie。下面举例说一下怎样通过配置禁止使用Cookie。

  打开项目sessionWeb的WebRoot目录下的META-INF文件夹(跟WEB-INF文件夹同级,如果没有则创建),打开context.xml(如果没有则创建),编辑内容如下: /META-INF/context.xml:

<?xml version='1.0' encoding='UTF-8'?>
    <Context path="/sessionWeb"cookies="false">
</Context>

或者修改Tomcat全局的conf/context.xml,修改内容如下: context.xml:

<!-- The contents of this file will be loaded for eachweb application -->
<Context cookies="false">
    <!-- ... 中间代码略 -->
</Context>

部署后TOMCAT便不会自动生成名JSESSIONID的Cookie,Session也不会以Cookie为识别标志,而仅仅以重写后的URL地址为识别标志了

注意:该配置只是禁止Session使用Cookie作为识别标志,并不能阻止其他的Cookie读写。也就是说服务器不会自动维护名为JSESSIONID的Cookie了,但是程序中仍然可以读写其他的Cookie。

8、Cookie与Session的区别

1、cookie数据存放在客户的浏览器上,session数据放在服务器上;
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session;
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。考虑到减轻服务器性能方面,应当使用COOKIE;(分布式中使用Redis实现Session,可有效解决该问题,具体实现日后再更)
4、单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能超过3K;
Cookie和Session的方案虽然分别属于客户端和服务端,但是服务端的session的实现对客户端的cookie有依赖关系的,上面我讲到服务端执行session机制时候会生成session的id值,这个id值会发送给客户端,客户端每次请求都会把这个id值放到http请求的头部发送给服务端,而这个id值在客户端会保存下来,保存的容器就是cookie,因此当我们完全禁掉浏览器的cookie的时候,服务端的session也会不能正常使用(注意:有些资料说ASP解决这个问题,当浏览器的cookie被禁掉,服务端的session任然可以正常使用,ASP我没试验过,但是对于网络上很多用php和jsp编写的网站,我发现禁掉cookie,网站的session都无法正常的访问)。

参考来源:

https://my.oschina.net/xianggao/blog/395675?fromerr=GC9KVenE

Comments are closed.