欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Web开发】说说Session和Cookie

程序员文章站 2022-07-14 15:33:55
...

 Session 与 Cookie 的作用都是为了保持访问用户与后端服务器的交互状态。它们有各自的优点,也有各自的缺陷,使用 Cookie 来传递信息时,随着 Cookie 个数的增多和访问量的增加,它占用的网络带宽也很大,试想假如 Cookie 占用 200 个字节,如果一天的 PV 有几亿,它要占用多少带宽?所以有大访问量的时候希望用 Session,但是 Session 的致命弱点是不容易在多台服务器之间共享,所以这也限制了 Session 的使用。

 

Cookie

 

Cookie 的作用我想大家都知道,通俗地说就是当一个用户通过 HTTP 协议访问一个服务器的时候,这个服务器会将一些 Key/Value 键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在条件符合时这个用户下次访问这个服务器的时候,数据又被完整地带回给服务器。

 

这个作用就像您去超市购物时,第一次给您办张购物卡,这个购物卡里存放了一些您的个人信息,下次您再来这个连锁超市时,超市会识别您的购物卡,下次直接购物就好了。

当初 W3C 在设计 Cookie 时实际上考虑的是为了记录用户在一段时间内访问 Web 应用的行为路径。由于 HTTP 协议是一种无状态协议,当用户的一次访问请求结束后,后端服务器就无法知道下一次来访问的还是不是上次访问的用户,在设计应用程序时,我们很容易想到两次访问是同一人访问与不同的两个人访问对程序设计和性能来说有很大的不同。例如,在一个很短的时间内,如果与用户相关的数据被频繁访问,可以针对这个数据做缓存,这样可以大大提高数据的访问性能。Cookie 的作用正是在此,由于是同一个客户端发出的请求,每次发出的请求都会带有第一次访问时服务端设置的信息,这样服务端就可以根据 Cookie 值来划分访问的用户了。

 

当前 Cookie 有两个版本:Version 0 和 Version 1。通过它们有两种设置响应头的标识,分别是 “Set-Cookie”和“Set-Cookie2”。这两个版本的属性项有些不同。

 

Set-Cookie

属性项 属性项介绍
NAME=VALUE 键值对,可以设置要保存的 Key/Value,注意这里的 NAME 不能和其他属性项的名字一样
Expires 过期时间,在设置的某个时间点后该 Cookie 就会失效,如 expires=Wednesday, 09-Nov-99 23:12:40 GMT
Domain 生成该 Cookie 的域名,如 domain="xulingbo.net"
Path 该 Cookie 是在当前的哪个路径下生成的,如 path=/wp-admin/
Secure 如果设置了这个属性,那么只会在 SSH 连接时才会回传该 Cookie


Set-Cookie2

属性项 属性项介绍
NAME=VALUE        与 Version 0 相同
Version 通过 Set-Cookie2 设置的响应头创建必须符合 RFC2965 规范,如果通过 Set-Cookie 响应头设置,默认值为 0,如果要设置为 1,则该 Cookie 要遵循 RFC 2109 规范
Comment 注释项,用户说明该 Cookie 有何用途
CommentURL 服务器为此提供的 URI 注释
Discard 是否在会话结束后丢弃该 Cookie 项,默认为 fasle
Domain 类似于 Version 0
Max-Age 最大失效时间,与 Version 0 不同的是这里设置的是在多少秒后失效
Path 类似于 Version 0
Port 该 Cookie 在什么端口下可以回传服务端,如果有多个端口,以逗号隔开,如 Port="80,81,8080"
Secure 类似于 Version 0

 

两个版本的 Cookie 中设置的 Header 头的标识符是不同的,我们常用的是 Set-Cookie:userName=“junshan”; Domain=“xulingbo.net”,这是 Version 0 的形式。针对 Set-Cookie2 是这样设置的:Set-Cookie2:userName=“junshan”; Domain=“xulingbo.net”; Max-Age=1000。但是在 Java Web 的 Servlet 规范中并不支持 Set-Cookie2 响应头,在实际应用中 Set-Cookie2 的一些属性项却可以设置在 Set-Cookie 中,如这样设置:Set-Cookie:userName=“junshan”; Version=“1”;Domain=“xulingbo.net”;Max-Age=1000。

 

当我们用如下方式创建 Cookie 时:

 

String getCookie(Cookie[] cookies, String key) { 
        if (cookies != null) { 
            for (Cookie cookie : cookies) { 
                if (cookie.getName().equals(key)) { 
                    return cookie.getValue(); 
                } 
            } 
        } 
        return null; 
    } 

    @Override 
    public void doGet(HttpServletRequest request, 
                      HttpServletResponse response) 
            throws IOException, ServletException { 
        Cookie[] cookies = request.getCookies(); 
        String userName = getCookie(cookies, "userName"); 
        String userAge = getCookie(cookies, "userAge"); 
        if (userName == null) { 
            response.addCookie(new Cookie("userName", "junshan")); 
        } 
        if (userAge == null) { 
            response.addCookie(new Cookie("userAge", "28")); 
        } 
        response.getHeaders("Set-Cookie"); 
 } 

 

Cookie 是如何加到 HTTP 的 Header 中的?当我们用 Servlet 3.0 规范来创建一个 Cookie 对象时,该 Cookie 既支持 Version 0 又支持 Version 1,如果您设置了 Version 1 中的配置项,即使您没有设置版本号,Tomcat 在最后构建 HTTP 响应头时也会自动将 Version 的版本设置为 1。

 

Session

 

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

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

 

那么Session 如何基于 Cookie 来工作?

 

有三种方式:

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

第一种情况下,当浏览器不支持 Cookie 功能时,浏览器会将用户的 SessionCookieName 重写到用户请求的 URL 参数中,它的传递格式如 /path/Servlet;name=value;name2=value2? Name3=value3,其中“Servlet;”后面的 K-V 就是要传递的 Path Parameters,服务器会从这个 Path Parameters 中拿到用户配置的 SessionCookieName。关于这个 SessionCookieName,如果在 web.xml 中配置 session-config 配置项,其 cookie-config 下的 name 属性就是这个 SessionCookieName 值。如果没有配置了 session-config 配置项,默认的 SessionCookieName 就是大家熟悉的“JSESSIONID”。需要说明的一点是,与 Session 关联的 Cookie 与其他 Cookie 没有什么不同。接着 Request 根据这个 SessionCookieName 到 Parameters 中拿到 Session ID 并设置到 request.setRequestedSessionId 中。

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

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

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

相关标签: Session Cookie