Tomcat到底是个啥猫

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tomcat到底是个啥猫相关的知识,希望对你有一定的参考价值。

参考技术A Tomcat是一种web服务器,也可以称作运行在服务器(物理意义上的计算机)上的一种软件包。用来对服务器上的html文档提供访问权限控制。

万维网本质上就是“超文本文档”(HTML文档)组成的一个通过超级链接互相访问交互网络。你从甲计算机上的文档A通过超链接访问乙计算机上的文档B,而B必须放在Web服务器(Tomcat)里才能被访问。

Web服务器是指驻留于因特网上某种类型计算机的程序。当Web浏览器(客户端)连到服务器上并请求文件时,服务器将处理该请求并将文件发送到浏览器上,附带的信息会告诉浏览器如何查看该文件。服务器使用HTTP(超文本传输协议)进行信息交流。

Web服务器不仅能够存储信息,还能在用户通过Web浏览器提供的信息的基础上运行脚本和程序。
Web服务器可以解析HTTP协议,当Web服务器接收到一个HTTP请求,会返回一个HTTP响应,例如送回一个HTML页面。为了处理一个请求,Web服务器会委托其他程序例如JSP脚本,Servlets,ASP脚本,服务器端javascript等来响应一个静态页面或图片,进行页面跳转。

Tomcat中的应用程序是WAR文件,WAR是Sun提出的一种Web应用程序格式,与JAR类似,是许多文件的一个压缩包。这个包中的文件按照一定目录结构来组织,通常其根目录下包含有html和jsp文件,另外还会有WEB-INF目录,这个目录很重要啊,在WEB-INF目录下有web.xml和classers目录,web.xml是这个应用的配置文件,classes目录则包含编译好的servlet类和jsp或servlet所依赖的其他类。

1、Web Client向Servlet容器(Tomcat)发出Http请求。
2、Servlet容器接收Client端的请求。
3、Servlet容器创建一个HttpRequest对象,将Client的请求信息封装到这个对象中。
4、Servlet创建一个HttpResponse对象。
5、Servlet调用HttpServlet对象的service()方法,把HttpRequest对象和HttpResponse对象作为参数传递给HttpServlet对象中,调用Servlet的doGet()或doPost()方法
6、HttpServlet调用HttpRequest对象的方法,获取Http请求,并进行相应处理。
7、处理完成HttpServlet调用HttpResponse对象的方法,返回相应数据。
8、Servlet容器把HttpServlet的响应结果传回客户端。

深入Tomcat源码分析Session到底是个啥!

Session到底是个啥?


我们都知道,HTTP协议本身是无状态的(Stateless),这对于一些简单的页面展示来说,功能足够,不受影响。而对于日渐复杂的动态页面、应用,各种需要登录认证等场景,就力不从心了。试想对于一个已经登录的用户仍然一次次的提示登录,会是什么感受呢?


因此,多数需要保持状态的应用,就要保证客户端和服务端交互状态的一致。对于浏览器发起的多次请求,仅基于HTTP协议,是无法识别出是否为同一用户请求的。而为了保持客户端和服务端交互状态,可以采取一系列的策略,例如:


  • Cookie

  • 隐藏form 表单域

  • Session

  • URL

  • SSL


本文将通过深入Tomcat源码,分析这一最常用的Servlet容器内部是如何使用Session来保持客户端与服务器状态一致的。


做为一名Web应用开发者,我们一定都听说过,甚至了解过Session这个词,以及其背后代表的一些概念。


Session,中文称之为会话,用于两个设备之间交互时状态的保持。因此,会话中至少要有一方需要保存会话的状态。


在Servlet规范中,session对象由HttpSession这一接口来表示,接口描述简明的概括了其主要作用


Provides a way to identify a user across more than one page request or

visit to a Web site and to store information about that user.


The servlet container uses this interface to create a session between an HTTP

client and an HTTP server. The session persists for a specified time period,

across more than one connection or page request from the user. A session

usually corresponds to one user.


而Tomcat内部则是通过StandardSession实现了HttpSession这个接口,内部统一使用StandardSession来处理。


在初次请求应用时,如果需要用到Session,则会创建之。一般的Servlet中并不会直接使用。而如果是请求JSP文件,由于JSP默认的隐式对象中是包含

session的,其在生成Servlet文件时,内部相当于包含了


HttpServletRequest.getSession(true)


因此,请求时会直接创建session对象。


创建session的过程,大致是下面的样子:


protected Session doGetSession(boolean create) {

// There cannot be a session if no context has been assigned yet

Context context = getContext();

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);

}


// Return the requested session if it exists and is valid

Manager 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) {

session.access();

return (session);

}

}


// Create a new session if requested and the response is not committed

if (!create) {

return (null);

}

if (response != null

&& context.getServletContext()

.getEffectiveSessionTrackingModes()

.contains(SessionTrackingMode.COOKIE)

&& response.getResponse().isCommitted()) {

throw new IllegalStateException(

sm.getString("coyoteRequest.sessionCreateCommitted"));

}


// Attempt to reuse session id if one was submitted in a cookie

// Do not reuse the session id if it is from a URL, to prevent possible

// phishing attacks

// Use the SSL session ID if one is present.

if (("/".equals(context.getSessionCookiePath())

&& isRequestedSessionIdFromCookie()) || requestedSessionSSL ) {

session = manager.createSession(getRequestedSessionId());

} else {

session = manager.createSession(null);

}


// Creating a new session cookie based on that session

if (session != null

&& context.getServletContext()

.getEffectiveSessionTrackingModes()

.contains(SessionTrackingMode.COOKIE)) {

Cookie cookie =

ApplicationSessionCookieConfig.createSessionCookie(

context, session.getIdInternal(), isSecure());

response.addSessionCookieInternal(cookie);

}

if (session == null) {

return null;

}

session.access();

return session;

}


整体流程基本是先判断是否已经存在session,如果没有则创建。如果有,则直接使用。


此时,需要注意两个问题:

  1. 初次请求时,session如何生成并传递给客户端的

  2. 后续的其它请求中,如果将客户端的请求与服务端已有的session建立关联的


上面代码中,判断session不存在并创建的过程,是直接调用createSession这个方法,并会根据sessionId是否为空,来确定是完全新创建session,还是恢复已有session。


public Session createSession(String sessionId) {

if ((maxActiveSessions >= 0) &&

(getActiveSessions() >= maxActiveSessions)) {

rejectedSessions++;

throw new TooManyActiveSessionsException(

sm.getString("managerBase.createSession.ise"),

maxActiveSessions); //注意这里有个策略

}

// Recycle or create a Session instance

Session session = createEmptySession();

// Initialize the properties of the new session and return it

session.setNew(true);

session.setValid(true);

session.setCreationTime(System.currentTimeMillis());

session.setMaxInactiveInterval(this.maxInactiveInterval);

String id = sessionId;

if (id == null) {

id = generateSessionId();

}

session.setId(id);

sessionCounter++;

SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);

synchronized (sessionCreationTiming) {

sessionCreationTiming.add(timing);

sessionCreationTiming.poll();

}

return (session);

}



这里有个Session超时时间,即最大空闲时间


注意此处maxInactiveInterval的值,即为我们默认的web.xml中提供的session超时时间(后台回复关键字004,了解更多),为30分钟。


在创建完Session之后,Tomcat通过在响应头中设置Set-Cookie这个MimeHeader来返回给客户端session数据。返回的数据是这样的:

JSESSIONID=CC4D83F3A61823AA8F980C89890A19D7; Path=/manager/; HttpOnly


设置Header的过程如下:

public void addSessionCookieInternal(final Cookie cookie) {

if (isCommitted()) { //此处判断,如果response已经提交,则不能再设置

return;

}

String name = cookie.getName();

final String headername = "Set-Cookie";

final String startsWith = name + "=";

String header = generateCookieString(cookie); //此处根据具体cookie的内容生成对应的串,内部会判断cookie的版本,过期时间等

if (!set) {

addHeader(headername, header);

} }



我们看到,初次请求时,响应头中包含了高亮的数据。

深入Tomcat源码分析Session到底是个啥!


那再次请求呢,我们看到这次响应头中没有sessionId的数据,而是转移到请求头中,并且是以Cookie的形式提供:

深入Tomcat源码分析Session到底是个啥!

此时,传到服务端,服务端解析Cookie对应的JSESSIOONID,并提取对应的sessionId值,与服务端对应的session数据做关联。


我们看代码中的实现


再次请求时,从Request中获取SessionCookie的地方在这里:

CoyoteAdapter.postParseRequset()


其内部调用 parseSessionCookiesId(request), 解析请求头中的cookie数据。

public void parseCookieHeader(MimeHeaders headers, ServerCookies serverCookies) {

// process each "cookie" header

int pos = headers.findHeader("Cookie", 0);

}

}


此处需要注意SessionCookie的名称是允许配置的,因此这一名称不一定一直都是JSESSIONID。


在解析Cookie获取SessionId之后,我们拿到的仅仅是一个字符串,还不能马上和Session关联起来,此时request会将此值赋值给其内部的一个名为

requestSessionId的属性。

当后面再次请求session时,就和我们最上面代码看到的一样,会有一个findSession的过程,深入Tomcat源码分析Session到底是个啥!


到此,我们基本了解了客户端浏览器和服务端Tomcat之间,如果保持交互状态的一致中的一种实现方式,即SessionCookie。


而本质上,这一过程就是传统上Socket交互的一个过程,我们完全可以自已写一段代码模拟返回响应的数据,只是需要注意响应头数据在HTTP规范中有特定的格式要求,如下,即数据之间要以CRLF分隔


总结下,客户端初次请求服务端会创建Session,此时通过在响应头中设置Set-Cookie将sessionId传递给客户端。后续客户端的请求会在请求头中设置Cookie项带上sessionId,从而保证客户端与服务端交互状态的一致。




以上是关于Tomcat到底是个啥猫的主要内容,如果未能解决你的问题,请参考以下文章

快速了解TomCat是个啥

TomCat弱口令扫描工具是个啥软件?

NoSQL到底是个啥?

被误解最大的基础学科——统计学,到底是个啥?

四层和七层网络模型,到底是个啥?

情感分析到底是个啥