zoukankan      html  css  js  c++  java
  • 深入理解Cookie与Session

    Session与Cookie的作用都是为了保持访问用户与后端服务器的交互状态。它们各有优点,也有各自的缺点。比如使用Cookie传递信息时,随着Cookie个数的增多和访问量的增加,它占用的网络带宽也很大,所有有大访问量时希望用Session,但是Session的致命缺点是不容易在多台服务器之间共享,这也限制了Sesssion的使用

    理解Cookie

    当一个用户通过Http访问一个服务器时,这个服务器会将一些Key/Value键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在条件符合时这个用户下次访问这个服务器时,数据又被完整地带回服务器

    当初W3C在设计Cookie时实际上考虑的是为了记录用户在一段时间内访问Web应用的因为路径。有于HTTP是一种无状态协议,当用户的一次访问请求结束后,后端服务器就无法直到下一次来访问的还是不是上次访问的用户。Cookie的作用正是如此,由于是同一个客户端发出的请求,每次发出的请求都会带着第一次访问时服务端设置的信息,这样服务端就可以根据Cookie值来划分访问的用户了

    Cookie的创建

    // 通过request获得Cookie,这里获取的是所有的Cookie数组,通过遍历数组找到需要的值
    Cookie[] cookies = request.getCookies();
    
    // 通过response设置Cookie,可以调用多次addCoookie方法添加多个Cookie
    response.addCookie(new Cookie("userName", "XXX"))
    

    所创建的Cookie的Name和Value的值不能设置为非ASCII字符,如果要使用中文,可以通过URLEncoder将其编码,否则会抛出IllegalArgumentException异常

    当我们通过response.addCookie创建多个Cookie时,这些Cookie最终是在一个请求Header项中的

    默认没有设置Cookie的生命周期,则在浏览器关闭后Cookie就失效了,可以通过setMaxAge(秒)设置失效期

    当我们请求某个URL路径时,浏览器会根据这个URL路径将符合条件的Cookie放在Request请求头回传给服务端,服务端通过request.getCookies()来获取所有Cookie

    使用Cookie的限制

    Cookie是HTTP头中的一个字段,虽然HTTP对本身对这个字段没有多少限制,但是Cookie最终还是存储在浏览器里,所以不同的浏览器对Cookie的存储都有一些限制,一般对于Cookie数量限制在500个/每个域名下,Cookie的总大小在4000字节左右

    理解Session

    Cookie可以让服务端程序跟踪每个客户端的访问,但是每次客户端的访问必须回传这些Cookie,如果Cookie很多,则无形中增加了客户端和服务端的数据传输量,而Session的出现正是为了解决这个问题

    同一个客户端每次和服务端交互时,不需要每次都回传所有的Cookie值,而是只要传回一个ID,这个ID时客户端第一次访问服务器时生成的,而且每个客户端都是唯一的,这样每个可负担就有了一个唯一的ID,客户端只要传回这个ID就行了,这个ID通常是Name为JSESSIONID的一个Cookie

    Session与Cookie

    Session是基于Cookie工作的,实际上有三种方式可以让Session正常工作:

    • 基于URL Path Parameter,默认支持
    • 基于Cookie,如果没有修改Context容器的Cookie标识,则默认也是支持的
    • 基于SSL,默认不支持,只有connector.getAttributes("SSLEnabled")为true时才支持

    当浏览器不支持Cookie功能时,浏览器会将用户的SessionCookieName重写到用户请求的URL参数中,它的传递格式如/path/Servlet;name=value;name2=value2?param3=Value3,其中Servlet;后面跟着的K-V(name=value;name2=value2)就是要传递的Path Parameters,服务端会从这个Path Parameters中拿到用户配置的SessionCookieName,这个SesssionCookieName如果在web.xml中配置session-config配置项,其cookie-config下的name属性就是这个SessionCookieName的值;如果没有配置session-config配置项默认的就是我们熟悉的JSESSIONID

    如果客户端也支持Cookie,则Tomcat仍然会解析Cookie中的Session ID,并会覆盖URL中的Session ID

    如果是第三种情况,则会根据javax.servlet.request.ssl_session属性值设置Session ID

    Session如何工作

    有了Session ID服务端就可以创建HttpSession对象了,第一次触发是通过request.getSession()方法,如果当前的Session ID还没有对应的HttpSession对象,那么就创建一个新的,并将这个对象加到org.apache.catalina.Manager的Session容器中保存。Manager类将管理所有的Session生命周期,Session过期将被回收;服务器关闭没过期的Session将会持久化到硬盘。只要这个HttpSession对象存在,用户就可以根据Session ID来获取这个对象了,也就做到了对状态的保持

    在Tomcat中,从requst.getSession()方法中获取的HttpSession对象实际上StandardSession对象的门面对象StandardSessionFacade,也是采用的门面模式。实际上管理Session的org.apache.catalina.Manager类的实现类是org.apache.catalina.session.StandardManager,通过Session ID从StandardManager的session集合中取出StandardSession对象。一个Session ID对应一个访问的客户端,所以一个客户端也就对应一个StandardSession对象,这个对象才是真正保存我们创建的Session值

    Session在服务器端先保存在内存中,当容器关闭时(正常关闭)会持久化到硬盘,具体如下:

    当Servlet容器重启或关闭时,StandardManager类会调用upload方法将session集合中没有过期的StandardSesssion对象持久化,它会将所有的StandardSession对象持久化到一个以SESSIONS.ser为文件名的文件中。到Servlet容器重启时,也就是StandardManager初始化时,它将重新读取这个文件,解析出所有的Session对象,重新保存在StandardManager的Session集合中

    值得注意的要持久化Session对象,必须调用Servlet容器的stop命令关闭容器(正常关闭),而不能直接kill掉Servlet容器的进程。因为直接结束进程,Servlet容器就没有机会调用upload方法来持久化这些Session对象

    Session对象在Servlet容器中并不是永远存在的,否则内存很容易被耗尽,所以必须给每个Session一个失效期,超过这个时间则Session对象将被清除。Tomcat中Session的有效期是30分钟,在代码中使用Session对象的setMaxInactiveInterval(秒)设置失效时间。检查每个Session是否失效是在Tomcat的一个后台线程中完成的,除了这个后台线程会检查外,当调用requeest.getSession()时也会检查该Session是否过期

    值得注意的是,request.getSession方法调用永远会返回一个Session对象(StandardSessoin),即使与这个客户端关联的Session对象已经过期。如果过期,则又会重新创建一个全新的Session,但是以前那个设置的Session值将会丢失。所以如果使用session.getAttribute取不到前面设置的Session值,很可能是Session过期了

    如果不想让Session过期可以设置setMaxInactiveInterval(-1),但是需要估下网站的访问量和设置的Session大小,防止Servlet容器内存被撑爆。如果不想自动创建Session对象,也可以通过request.getSession(boolean create)方法来判断该客户端关联的Session对象是否存在,true:Session失效后会自动创建新对象,实际上和无参的方法一致;false:如果当前Session不存在不会自动创建新对象

    Cookie的安全性

    Cookie通过把所有要保存的数据通过HTTP的头部从服务端传递到客户端,又从客户端回传给服务端,所有的数据保存在客户端的浏览器里,所以这些Cookie数据可以在直接访问到

    相比较而言Session的安全性要高很多,因为Session是将数据保存在服务端,只是通过Cookie传递一个Session ID而已,所以Session更适合存储用户隐私和重要的数据

    Cookie压缩

    Cookie在HTTP头部。所以通常的gzip和deflate针对请求body的压缩不能压缩Cookie,如果Cookie的量很大,则需要手动对Cookie压缩,压缩方式是将Cookie的k/v当作普通文本,做文本压缩。压缩算法同样可以使用gzip和deflate算法。值得注意的是,根据Cookie规范,在Cookie中不能包含控制字符,仅能包含ASCII码为34~126的可见字符。所以要将压缩后的结果再进行转码,可以进行Base32和Base64编码

    使用deflater压缩,压缩后使用Base64编码

    // deflater压缩
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    DeflaterOutputStream dos = new DeflaterOuterOutputStream(bos);
    dos.write("数据".getBytes());
    dos.close();
    // Base64编码
    String compress = new sun.misc.BASE64Encoder().encode(bos.toByteArray());
    response.addCookie(new Cookie("compress", compress));
    

    先使用Base64解码,再使用Inflater解码

    // Base64解码
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    byte[] compress = new sun.misc.BASE64Decoder().decodeBuffer("数据");
    // inflater解码
    ByteArrayInputStream bis = new ByteArrayInputStream(compress);
    InfalterInputStream inflater = new InflaterInputStream(bis);
    byte[] b= new byte[1024];
    int count = 0;
    while ((count = inflater.read(b)) >= 0) {
        out.write(b, 0, count);
    }
    inflater.close();
    System.out.println(new String(out.toByteArray());
    

    解决表单重复提交问题

    要防止表单重复提交就需要标识用户每一次访问请求,使得每一次访问对服务端来说都是唯一确定的。为了标识用户每次访问请求,可以在表单域中添加一个隐藏域,这个隐藏域的值每次都是唯一的,当打开表单时通过后台生成一个唯一的值,并设置到表单的隐藏域中,同时保存到Session中;提交表单时就会将隐藏域值回传与Session中的值对比,如果一致则说明没有重复提交可以后续处理,并删除该Session值;如果两个值比对不上说明这次提交不合法

    多终端登录

    目前很多网站都会有通过移动端扫码登陆的情况,可以通过如下方式实现:这里移动端设备必须是已经登录的状态,因为这样才知道到底是谁要登录的信息,同时扫码的二维码也带着一个特殊标识,标识是这个客户通过手机登录了,当手机端扫码成功后,会在服务端设置这个二维码对应的标识为登录成功,这是PC客户端会通过轮询请求发送服务端(可以通过定时器),来验证标识位是否已经设置来判断能否登录

  • 相关阅读:
    108. Convert Sorted Array to Binary Search Tree
    107. Binary Tree Level Order Traversal II
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    104. Maximum Depth of Binary Tree
    103. Binary Tree Zigzag Level Order Traversal
    102. Binary Tree Level Order Traversal
    系统和进程相关信息
    文件I/0缓冲
    系统编程概念(文件系统mount等函数的使用)
  • 原文地址:https://www.cnblogs.com/lz2017/p/14352455.html
Copyright © 2011-2022 走看看