会话管理机制:Cookie和Session

一、什么是会话

会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。

每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,程序要想办法为每个用户保存这些数据。例如:用户点击超链接通过一个servlet购买了一个商品,程序应该想办法保存用户购买的商品,以便于用户点结帐servlet时,结帐servlet可以得到用户购买的商品为用户结帐。那么很显然,我们需要实现一个技术来在整个会话中保存数据。在我们以前需要到的servlet的域当中,我们已经学习了ServletContext域和request域,其中request域的作用范围只在一个请求中,没法在整个会话中作用。而ServletContext域的作用范围是整个web应用,当不同用户产生不同会话的时候前一个用户产生的数据会被后一个用户产生的数据覆盖。所以这两个域都不能用来保存会话中的数据。那么如何保存会话数据,常见的有两种会话技术:Cookie和Session。

Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。

Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。

Cookie与Session都可以进行会话跟踪,但是实现的原理不太一样。一般情况下二者均可以满足需求,但有时候不可以使用Cookie,有时候不可以使用Session。下面具体来了解这两种会话技术。

二、Cookie技术

Java EE提供了一个类Cookie实现Cookie操作,在javax.servlet.http包下面。Cookie是基于set-Cookie响应头和Cookie请求头工作的,服务器可以发送set-Cookie请求头命令浏览器保存一个cookie信息,浏览器会在访问服务器时以Cookie请求头的方式带回之前保存的信息。

输出上一次访问浏览器时间的示例:

    import java.io.IOException;
    import java.util.Date;

    import javax.servlet.ServletException;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    public class CookieDemo1 extends HttpServlet {

        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            response.setContentType("text/html;charset=utf-8");

            Cookie []  cs = request.getCookies();
            Cookie findC = null;
            if(cs!=null){
                for(Cookie c : cs){
                    if("lastTime".equals(c.getName())){
                        findC = c;
                    } 
                }
            }
            if(findC == null){
                response.getWriter().write("您是第一次访问本网站!");
            }else{
                Long lastTime = Long.parseLong(findC.getValue());
                response.getWriter().write("您上次访问时间是:"+new Date(lastTime).toLocaleString());
            }


            response.addCookie(c);
        }

        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            doGet(request, response);
        }   
    }

Cookie类中常用的方法:

1. request.getCookies();

返回一个Cookie数组,可以对Cookie进行遍历,注意实际使用中要进行空值判断

2. response.addCookie(Cookie c);

3. new Cookie(String name, String value)

Cookie在构造的时候就需要设定好cookie的名字和值

4. getName();

5. setValue与getValue方法

6. setMaxAge与getMaxAge方法

一个Cookie如果没有设置过MaxAge则这个Cookie是一个会话级别的Cookie,这个Cookie信息打给浏览器后浏览器会将它保存在浏览器的内存中,这意味着只要浏览器一关闭,随着浏览器内存的销毁,Cookie信息也就消失了。一个Cookie也可以设置MaxAge,浏览器一旦发现收到的Cookie被设置了MaxAge,则会将这个Cookie信息以文件的形式保存在浏览器的临时文件夹中,保存到指定的时间到来为止。这样一来即使多次开关浏览器,由于这些浏览器都能在临时文件夹中看到cookie文件,所以在cookie失效之前cookie信息都存在。设置的时间值的单位为秒。

Date date = new Date();
Cookie c = new Cookie("lastTime",date.getTime()+"");
c.setMaxAge(3600*24*30);

7. setPath与getPath方法
用来通知浏览器在访问服务器中的哪个路径及其子路径时带着当时的cookie信息过来。如果不明确设置,则默认的路径时发送Cookie的servlet路径。

c.setPath(request.getContextPath());

8. setDomain与getDomain方法
用来通知浏览器在访问哪个域名的时候带着当前的cookie信息。但是要注意,现代的浏览器一旦发现cookie设置过domain信息则会拒绝接受这个Cookie。所以我们平常不要设置这个方法。

c.setDomain(".baidu.com");

Cookie的一个典型应用:显示用户上次访问的商品

Cookie使用的注意细节:

  1. 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
  2. 一个Web站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。
  3. 浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。如果站点存放的Cookie数太多,可能会出现Cookie信息被覆盖的情况。
  4. 删除Cookie时,path必须一致,否则不会删除(浏览器通过cookie的name+path来标识一个Cookie)。在设别cookie的时候是name+path+(domain),想要命令浏览器删除一个Cookie可以发送一个同名同path的cookie,并将maxAge设为0,cookie会覆盖并立即超时后删除。

三、Session技术

在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。

session是一个域对象,作用范围为当前整个会话。生命周期:当程序第一次调用到request.getSession()方法时说明客户端明确需要用到session,此时创建出对应客户端的session对象。当session超过30分钟(这个时间是可以在web.xml文件中进行修改的)没有人使用则认为session超时销毁这个session。如果程序中明确调用session.invalidate()方法可以立即杀死session。又或者当服务器被非正常关闭时,随着虚拟机的死亡而死亡。如果服务器是正常关闭,还未超时的session会被以文件的形式保存在服务器的work目录下,这个过程叫做session的 钝化。下次再正常启动服务器时,钝化着的session会被恢复到内存中,这个过程叫做session的 活化

Session和Cookie的主要区别在于:Cookie是把用户的数据写给用户的浏览器。Session技术把用户的数据写到用户独占的session中。

Session的原理:

request.getSession()方法会检查请求中有没有JSESSIONID cookie,如果有拿出它的值找到对应的Session为它服务。如果没有则检查请求的URL后有没有以参数的形式带着JESSIONID 过来,如果有则找到对应的Session为浏览器服务。如果还找不到,则创建一个Session然后在响应中添加JSESSIONID cookie,值就是这个session的ID值。默认情况下,JESSIONID 的path为当前web应用的名称,并没有设置过MaxAge,是一个会话级别的Cookie。这意味着一旦关闭浏览器再新开浏览器时,由于JSESSIONID丢失,会找不到之前的Session,我们可以手动的发送JESSIONID cookie,名字和path设置和自动发送时一样,但是设置一下MaxAge,使浏览器除了在内存中保存JESSIONID信息以外还在临时文件夹中以文件的形式保存,这样即使重开浏览器仍然可以使用之前的Session。

URL重写

如果浏览器禁用了Cookie,浏览器就没有办法JESSIONID cookie,这样就用不了session了。我们可以使用URL重写的机制,在所有的超链接后都以参数的形式拼接JESSIONID信息,从而在点击超链接时可以使用URL参数的方式带回JESSIONID,从而使用Session。将URL进行重写拼接上JESSIONID的过程就叫做URL重写

    request.getSession()
    //在URL重写之前一定要先创建出Session,才有Session id,才能进行重写
    response. encodeURL(java.lang.String url)
    //用于对表单action和超链接的url地址进行重写,一般的地址都用这个方法重写
    response. encodeRedirectURL(java.lang.String url) 
    //如果地址是用来进行重定向的则使用这个方法

注意: URL重写的方法一旦发现浏览器带回了任意 Cookie信息,则认为客户端没有禁用cookie,就不会再进行重写操作了。

案例:实现登录、注销功能

四、Session与Cookie的比较

1、 从存取方式上比较

Cookie中只能保存ASCII字符串,如果需要存取Unicode字符或者二进制数据,需要进行UTF-8,GBK或者BASE64等方式的编码。Cookie中也不能直接存取Java对象。若要存储复杂的信息,使用Cookie是比较困难的。

Session中可以存取任何类型的数据,包括而不限于String、Integer、List、Map等。Session中也可以直接保存Java Bean乃至Java类,对象等,使用起来非常方便,可以把Session看做是一个Java容器类。

2、从隐私安全上比较

Cookie存储在客户端浏览器中,对客户端是可见的,客户端的一些程序可能会窥探、复制甚至修改Cookie中的内容。而Session存储在服务器上,对客户端是透明的,不存在敏感信息泄露的危险。如果选用Cookie,比较好的办法是,敏感的信息如账号密码等尽量不要写到Cookie中。

3、从有效期上比较

通过设置Cookie的maxAge属性为一个很大很大的数字或者Integer.MAX_VALUE可以使得浏览器长久地记录用户的登录信息。使用Session理论上也能实现这种效果。只要调用方法setMaxInactiveInterval(Integer.MAX_VALUE)就可以了。但是由于Session依赖于名为JESSIONID的Cookie,而这个Cookie的maxAge默认为-1,只要关闭了浏览器Session就会失效,因此Session不能实现信息永久有效的效果。使用URL地址重写也不能实现。而且如果设置Session的超时时间过长,服务器累计的Session就会越多,越容易导致内存溢出。

4、对服务器的负担上比较

Session是保存在服务器端的,每个用户都会产生一个Session。如果并发访问的用户非常多,会产生非常多的Session,消耗大量的内存。因此像Google、Baidu这样并发访问量极高的网站,是不太可能使用Session来追踪客户会话的。而Cookie保存在客户端,不占用服务器资源。如果并发浏览的用户非常多,Cookie是很好的选择。

5、从浏览器支持上比较

Cookie是需要客户端浏览器支持的。如果客户端禁用了Cookie,或者不支持Cookie,则会话跟踪会失效。对于WAP上的应用,常规的Cookie就派不上用场了。如果客户端浏览器不支持Cookie,需要使用Session以及URL地址重写。需要注意的是所有的用到Session程序的URL都要使用response.encodeURL(String URL)或者response.encodeRedirectURL(String URL)进行URL地址重写,否则导致Session会话跟踪失败。对于WAP应用来说,Session+URL地址重写也许是它唯一的选择。如果客户端支持Cookie,则Cookie既可以设为本浏览器窗口以及子窗口内有效(把maxAge设为-1),也可以设为所有浏览器窗口内有效(把maxAge设为某个大于0的整数)。但Session只能在本浏览器窗口以及子窗口内有效。如果两个浏览器窗口互不相干,它们将使用两个不同的Session。

6、从跨域名上比较

Cookie支持跨域名访问,而Session不会支持跨域名访问。Session仅在他所在的域名内有效。

你可能感兴趣的:(java-web)