Tomcat 服务器 Session的实现

原创 2016年05月31日 21:43:54

session

结合《HTTP权威指南》和《How Tomcat Works》话一话我所理解的Session以及Tomcat下的实现方式!


Session是什么?

在开始正式讨论之前,我们首先探讨一些原理性的问题,什么是session,它可以用来做什么!
我们每天都会浏览各种网站,不同的用户浏览网站的目的不同,在该网站上留下的历史也不同,为了提供个性化的服务,服务器就需要记录和识别用户!一个用户可以在不同地方,利用不同设备访问网站,服务器如何知道“我是谁”呢?很多人一下子就想到用户名和密码,对没错,这的确是一种方式。但是网站访问是一个连续的过程,每次访问都携带用户名和密码的做法提高了用户风险,更重要的是,如何解决非注册用户的问题呢,一些用户习惯每天打开新闻站点,但是他只是浏览信息,不想输入任何个人信息去注册网站,这样的用户如何提供个性化服务呢!

看看现实生活中政府是如何识别“我是谁”,并且提供差异服务的。我们每个人都有一张身份证,是政府机关发给我们的。身份证只是一个人的基本信息,例如姓名,身份证号,住址。上面并不会纪录你的学历,你的婚姻状况。当我需要这些信息的时候,我们提供身份证,相关的单位就会提供相关证明,例如在很多省份在购买房产的时候,需要未婚人士提供一个单身证明,我们只要向相应的政府机构提供身份证,就可以获取到这些“被认可的”信息。
可以抽象的理解为,政府颁发了一个身份证给个人,当你需要政府服务的时候,只需要提供你的身份证,这样政府就会从它自己维护的数据中,获取你的更多个人信息,提供差异化服务。
身份证会具有有效期,当身份证过期的时候,需要从新申请,否则持有的身份证就会无效。

哪么,可否效仿这个过程,网站服务器“颁发”一个身份证给用户,用户每次访问都带着这个身份证,网站服务器根据这个身份证获取用户更多信息,这样不就可以获取个性化服务了么!当身份证过期的时候,需要用户从新申请。

现在我们要讨论的问题渐渐浮出水面了。我们和服务器之间的交互过程,可以理解为一个Session,直白的翻译就是一次会话,而每次我们携带的身份信息,是通过Cookie的方式实现的。

在《HTTP权威指南中》这样描述了用Cookie实现的身份认证过程。

cookie

Cookie的作用就好像服务器,给用户发的一个身份证,上面写着,“我叫XX,地址”,用户访问服务器的时候,携带着这些信息,服务器会读取所有的这些信息。

用户首次访问Web 站点时,服务器对用户一无所知。为了能够在用户下次访问的时候,识别出这个用户,站点给用户“拍上”一个独有的cookie,这样以后服务器就可以识别出这个用户了。Cookie包含了一个由名字=值这样的信息构成的列表,并通过Set-Cookie或者Set-Cookie2 HTTP响应首部返回给用户。浏览器再下次访问站点的时候,会在Cookie请求首部中,原封不动地携带服务器发送过来的Cookie数据。

其实Cookie的可以携带任意信息,它也是服务器维护用户Session的最常用的手段的一种。服务器真对用户的访问,创建一个拥有唯一ID的Session,然后通过Set-Cookie把这个SessionId贴到用户身上。用户每次访问服务器都带着这个SessionId,服务器就可以通过SessionId找出对应的Session对象,识别出用户了。

当然这仍然是很抽象的描述,不同的Web服务器实现这个机制也有很大差异。下面通过Tomcat的源代码来看一下Tomcat作为Web服务器,如何维护Session,如何根据Cookie来获取用户Session的。


Tomcat Session的实现

大概的流程可以分为如下几个步骤。

1. 从Cookie中获取SessionID

针对每一次用户的请求,HTTPProcessor负责解析用户请求,会对HTTP请求头部分析,如果发现存在jsessionid这样的cookie,就把cookie值set到HttpSevletRequest对象中

if (name.equals("cookie")) {
   Cookie cookies[] = RequestUtil.parseCookieHeader(value);
   for (int i = 0; i < cookies.length; i++) {
      if (cookies[i].getName().equals("jsessionid")) {
         // Override anything requested in the URL
         if (!request.isRequestedSessionIdFromCookie()) {
            // Accept only the first session id cookie
            request.setRequestedSessionId(cookies[i].getValue());
            request.setRequestedSessionCookie(true);
            request.setRequestedSessionURL(false);
         }
      }
      request.addCookie(cookies[i]);
   }
}

2. 获取Session,如果不存在创建新Session

当需要使用Session访问其中内容的时候,会调用Request的getSession方法

private HttpSession doGetSession(boolean create) {
        // There cannot be a session if no context has been assigned yet
        if (context == null)
            return (null);

        // Return the current session if it exists and is valid
        if ((session != null) && !session.isValid())
            session = null;
        if (session != null)
            return (session.getSession());

        // Return the requested session if it exists and is valid
        Manager manager = null;
        if (context != null)
            manager = context.getManager();

        if (manager == null)
            return (null);      // Sessions are not supported

        if (requestedSessionId != null) {
            try {
                session = manager.findSession(requestedSessionId);
            } catch (IOException e) {
                session = null;
            }
            if ((session != null) && !session.isValid())
                session = null;
            if (session != null) {
                return (session.getSession());
            }
        }

        // Create a new session if requested and the response is not committed
        if (!create)
            return (null);
        if ((context != null) && (response != null) &&
            context.getCookies() &&
            response.getResponse().isCommitted()) {
            throw new IllegalStateException
              (sm.getString("httpRequestBase.createCommitted"));
        }

        session = manager.createSession();
        if (session != null)
            return (session.getSession());
        else
            return (null);

}

简而言之如果之前设置过SessionId,那么request会在Manager中寻找Session,如果有则直接使用,如果不存在,那么就让Manager创建一个Session。

需要补充一点,Tomcat的Session的创建和维护是通过实现Manager接口实现的,其中StandardManager是标准实现,当然真对不同应用场景,例如集群Tomcat,Session需要各个服务器共享,则需要使用不同的Manager来实现Session的维护。

3. 如果Session存在,在Response中,设置SetCookie
在HTTPResponseBase中的SetHeader方法中,检查Request中Session对象是否存在,如果存在,则把SessionId写在Set-Cookie首部

if ((session != null) && session.isNew() && (getContext() != null) && getContext().getCookies()) {
	Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME, session.getId());
	cookie.setMaxAge(-1);
	String contextPath = null;
	if (context != null)
	    contextPath = context.getPath();
	if ((contextPath != null) && (contextPath.length() > 0))
	    cookie.setPath(contextPath);
	else
	    cookie.setPath("/");
	if (hreq.isSecure())
		cookie.setSecure(true);
	addCookie(cookie);
}

	// Send all specified cookies (if any)
synchronized (cookies) {
	Iterator items = cookies.iterator();
	while (items.hasNext()) {
		Cookie cookie = (Cookie) items.next();
		outputWriter.print(CookieTools.getCookieHeaderName(cookie));
		outputWriter.print(": ");
		outputWriter.print(CookieTools.getCookieHeaderValue(cookie));
		outputWriter.print("\r\n");
	}
}

其实

SESSION_COOKIE_NAME

就是JSESSIONID,至于tomcat为什么使用这个字符串,可能就要和开发tomcat的程序员探讨一下了,其实她可以叫任何名字。
我们注意到在设置Cookie的时候,有一个CookieTools.getCookieHeaderName的方法,该方法根据HTTP版本号,决定使用Set-Cookie还是Set-Cookie2

public static String getCookieHeaderName(Cookie cookie) {
    int version = cookie.getVersion();

    if (version == 1) {
        return "Set-Cookie2";
    } else {
        return "Set-Cookie";
    }
}

 4. 浏览器验证

首先我初次请求服务器,浏览器发送的数据如下:
request

可以看出来,浏览器发送的Cookie中,不存在JSESSIONID,因此此刻Session还并没有创建和维护起来。

不过在服务器的Response中可以看到Set-Cookie 首部
response
此时,服务器已经把会话建立起来,并且分配了唯一的标示,并且告诉浏览器:“下次来要告诉我你是谁哦”

然后我们刷一下浏览器,再次请求服务器,可以看到Request如下:
nextrequest
可以看到,这次访问Cookie中已经加上了JSESSIONID,服务器可以利用这个SessionID,从本地找到Session对象,拿到记录下来的用户行为或者用户信息了。


 

 

相关文章推荐

Tomcat之session详解

深入Tomcat源码分析Session到底是个啥! Session到底是个啥? 我们都知道,HTTP协议本身是无状态的(Stateless),这对于一些简单的页面展...
  • mawming
  • mawming
  • 2016年08月17日 10:00
  • 1652

服务器SESSION实现原理(以PHP服务器为例)

session:在计算机中,尤其是在网络应用中,称为“会话”。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的...

【Session】多服务器节点间session共享

在做了web集群后,你肯定会首先考虑session同步问题,因为通过负载均衡后,同一个IP访问同一个页面会被分配到不同的服务器上,如果session不同步的话,一个登录用户,一会是登录状态,一会又不是...

N个tomcat之间实现Session共享

关于tomcat之间session共享的配置和解决方案。

tomcat session实现原理

服务器端实现原理 Session在服务器端具体是怎么实现的呢?我们使用session的时候一般都是这么使用的: request.getSession()或者request.getSession(t...
  • zbuger
  • zbuger
  • 2016年03月17日 10:36
  • 696

Tomcat Session管理机制(Tomcat源码解析七)

前面几篇我们分析了Tomcat的启动,关闭,请求处理的流程,tomcat的classloader机制,本篇将接着分析Tomcat的session管理方面的内容。 在开始之前,我们先来看一下总体上的结...

Tomcat如何禁用session(Turn off the Session in Tomcat )

有时候我们不需要用到session,而session在tomcat中是属于关键功能,它在启动的时候会自动创建,这样就会消耗一定的内存空间,如果访问量大了session就会产生很多。这样也不利于我们进行...
  • ywch520
  • ywch520
  • 2016年06月07日 20:27
  • 2981

tomcat为什么要禁用session?

我们先来做一个实验,用jmeter对tomcat下的一个jsp页面做压测: (1)jsp的内容非常简单,1.jsp: 1.jsp this is 1.jsp 没有任何复杂的处理,只...

Tomcat之Session和Cookie大揭密

一、JSP和Servlet中的Cookie      由于HTTP协议是无状态协议(虽然Socket连接是有状态的,但每次用HTTP协议进行数据传输后就关闭的Socket连接,因此,HTTP协议...

分布式Session的几种实现方式

一。分布式Session的几种实现方式 1.基于数据库的Session共享 2.基于NFS共享文件系统 3.基于memcached 的session,如何保证 memcached 本身的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Tomcat 服务器 Session的实现
举报原因:
原因补充:

(最多只允许输入30个字)