TOMCAT原理以及处理HTTP请求的过程、ContextPath ServletPath

本文详细介绍了Tomcat服务器的内部架构,包括Server、Service、Connector、Engine、Host和Context等核心组件的工作原理及其交互过程。同时,还深入探讨了请求如何在这些组件间传递,以及ContextPath、ServletPath和PathInfo的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、TOMCAT

1 - Tomcat Server的组成部分
1.1 - Server

A Server element represents the entire Catalina servlet container. (Singleton)

1.2 - Service

A Service element represents the combination of one or more Connector components that share a single Engine
Service是这样一个集合:它由一个或者多个Connector组成,以及一个Engine,负责处理所有Connector所获得的客户请求

1.3 - Connector

一个Connector将在某个指定端口上侦听客户请求,并将获得的请求交给Engine来处理,从Engine处获得回应并返回客户
TOMCAT有两个典型的Connector,一个直接侦听来自browser的http请求,一个侦听来自其它WebServer的请求
Coyote Http/1.1 Connector 在端口8080处侦听来自客户browser的http请求
Coyote JK2 Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求

1.4 - Engine

The Engine element represents the entire request processing machinery associated with a particular Service
It receives and processes all requests from one or more Connectors
and returns the completed response to the Connector for ultimate transmission back to the client
Engine下可以配置多个虚拟主机Virtual Host,每个虚拟主机都有一个域名
当Engine获得一个请求时,它把该请求匹配到某个Host上,然后把该请求交给该Host来处理
Engine有一个默认虚拟主机,当请求无法匹配到任何一个Host上的时候,将交给该默认Host来处理

1.5 - Host


代表一个Virtual Host,虚拟主机,每个虚拟主机和某个网络域名Domain Name相匹配
每个虚拟主机下都可以部署(deploy)一个或者多个Web App,每个Web App对应于一个Context,有一个Context path
当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理
匹配的方法是“最长匹配”,所以一个path==""的Context将成为该Host的默认Context
所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配

1.6 - Context

一个Context对应于一个Web Application,一个Web Application由一个或者多个Servlet组成
Context在创建的时候将根据配置文件$CATALINA_HOME/conf/web.xml和$WEBAPP_HOME/WEB-INF/web.xml载入Servlet类
当Context获得请求时,将在自己的映射表(mapping table)中寻找相匹配的Servlet类
如果找到,则执行该类,获得请求的回应,并返回


假设来自客户的请求为:
http://localhost:8080/wsota/wsota_index.jsp

1) 请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得

2) Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应

3) Engine获得请求localhost/wsota/wsota_index.jsp,匹配它所拥有的所有虚拟主机Host

4) Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)

5) localhost Host获得请求/wsota/wsota_index.jsp,匹配它所拥有的所有Context

6) Host匹配到路径为/wsota的Context(如果匹配不到就把该请求交给路径名为""的Context去处理)

7) path="/wsota"的Context获得请求/wsota_index.jsp,在它的mapping table中寻找对应的servlet

8) Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类

9) 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法

10)Context把执行完了之后的HttpServletResponse对象返回给Host

11)Host把HttpServletResponse对象返回给Engine

12)Engine把HttpServletResponse对象返回给Connector

13)Connector把HttpServletResponse对象返回给客户browser

 

二、Context Path、Servlet Path、Path info

                        |-- Context Path --|-- Servlet Path -|--Path Info--|
http://www.myserver.com /mywebapp /helloServlet /hello
|-------- Request URI ----------------------------|

Remember the following three points:
1. Request URI = context path + servlet path + path info.
2. Context paths and servlet paths start with a / but do not end with it.
3. HttpServletRequest provides three methods getContextPath(),
    getServletPath() and getPathInfo() to retrieve the context path,
    the servlet path, and the path info, respectively, associated with a request.


Identifying the servlet path
To match a request URI with a servlet, the servlet container follows a simple algorithm.
Once it identifies the context path, if any, it evaluates the remaining part of the
request URI with the servlet mappings specified in the deployment descriptor, in the
following order. If it finds a match at any step, it does not take the next step.

1 The container tries to match the request URI to a servlet mapping. If it finds a
match, the complete request URI (except the context path) is the servlet path. In
this case, the path info is null.
2 It tries to recursively match the longest path by stepping down the request URI
path tree a directory at a time, using the / character as a path separator, and determining
if there is a match with a servlet. If there is a match, the matching part
of the request URI is the servlet path and the remaining part is the path info.
3 If the last node of the request URI contains an extension (.jsp, for example),
the servlet container tries to match it to a servlet that handles requests for the
specified extension. In this case, the complete request URI is the servlet path
and the path info is null.
4 If the container is still unable to find a match, it will forward the request to the
default servlet. If there is no default servlet, it will send an error message indicating
the servlet was not found.

<servlet-mapping>
    <servlet-name>RedServlet</servlet-name>
    <url-pattern>/red/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>RedServlet</servlet-name>
    <url-pattern>/red/red/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>RedBlueServlet</servlet-name>
    <url-pattern>/red/blue/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>BlueServlet</servlet-name>
    <url-pattern>/blue/</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>GreenServlet</servlet-name>
    <url-pattern>/green</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>ColorServlet</servlet-name>
    <url-pattern>*.col</url-pattern>
</servlet-mapping>


Request URI                Servlet Used            Servlet Path        Path Info
/colorapp/red                RedServlet              /red                 null
/colorapp/red/               RedServlet              /red                 /
/colorapp/red/aaa            RedServlet              /red                 /aaa

/colorapp/red/blue/aa        RedBlueServlet          /red/blue            /aa
/colorapp/red/red/aaa        RedServlet              /red/red             /aaa
/colorapp/aa.col             ColorServlet            /aa.col              null

/colorapp/hello/aa.col       ColorServlet            /hello/aa.col        null
/colorapp/red/aa.col         RedServlet              /red                 /aa.col
/colorapp/blue               NONE(Error message)                         
/colorapp/hello/blue/        NONE(Error message)                         
/colorapp/blue/mydir         NONE(Error message)
    
/colorapp/blue/dir/aa.col    ColorServlet            /blue/dir/aa.col     null 
/colorapp/green              GreenServlet            /green               null

 


<think>我们正在处理用户关于Tomcat升级后出现的错误:javax.servlet.http.HttpServletRequest.getHttpServletMapping的问题。 根据用户描述,错误发生在升级Tomcat之后,涉及HttpServletRequest的getHttpServletMapping方法。这通常是因为Servlet API版本不兼容导致的。 分析: 1. `getHttpServletMapping` 方法是Servlet 4.0引入的(Java EE 8的一部分)。如果用户的应用代码中使用了这个方法,那么运行环境必须支持Servlet 4.0。 2. Tomcat 9.0.x开始支持Servlet 4.0,而Tomcat 8.5.x支持的是Servlet 3.1。 3. 因此,如果用户从较低版本(如Tomcat 8.5)升级到Tomcat 9.0或更高版本,但应用程序仍然编译时使用的是旧版本的Servlet API(比如Servlet 3.1),那么在运行时就会找不到这个方法(NoSuchMethodError)。 解决方案: 1. 确保Tomcat版本至少为9.0.x(因为Tomcat 9.0实现了Servlet 4.0规范)。 2. 检查应用程序的依赖,确保编译时使用的Servlet API版本为4.0或更高。如果使用Maven,可以在pom.xml中检查: ```xml <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> ``` 注意:版本至少为4.0.0,且scope一般为provided,因为Tomcat本身会提供该API。 3. 如果应用程序之前是针对Tomcat 8.5(Servlet 3.1)开发的,那么需要将代码中使用的Servlet 4.0新特性(如getHttpServletMapping)进行条件处理,或者升级整个应用以使用Servlet 4.0。 4. 清理并重新构建项目,确保部署到Tomcat的WAR文件包含正确的类文件。 5. 如果用户无法升级到Tomcat 9(例如由于环境限制),那么应该避免使用Servlet 4.0的新特性,将代码中调用`getHttpServletMapping`的地方移除或替换为其他方式。 6. 另外,检查是否有其他库依赖于Servlet API的版本,确保没有版本冲突。 参考引用: 根据引用[2]中提到的错误,有时可能是由于多个servlet映射到同一个URL导致的,但这里的问题明显是方法不存在,所以更可能是版本问题。同时,引用[3]提到了Tomcat 8.5.46的更新日志,但该版本仍然只支持Servlet 3.1。 因此,如果用户升级到了Tomcat 9以下版本,那么需要升级Tomcat到9以上;如果已经使用Tomcat 9,则需要确保应用使用Servlet 4.0 API编译。 相关问题: 1. 如何检查当前Tomcat版本支持的Servlet API版本? 2. 如何解决升级Tomcat后出现的NoSuchMethodError? 3. Servlet 4.0相对于3.1有哪些主要新特性?</think>### Tomcat升级错误:`javax.servlet.http.HttpServletRequest.getHttpServletMapping()` 解决方案 此错误通常发生在升级Tomcat后,应用程序尝试调用`getHttpServletMapping()`方法时出现`NoSuchMethodError`或类似异常。根本原因是**Servlet API版本不兼容**,涉及Servlet规范3.1与4.0的差异: #### 原因分析 1. **方法版本不匹配** `getHttpServletMapping()`是Servlet 4.0规范新增的方法(Java EE 8),在Servlet 3.1(Java EE 7)中不存在。 - Tomcat 8.5.x 实现的是 **Servlet 3.1** 规范 - Tomcat 9.0.x+ 实现的是 **Servlet 4.0** 规范 - 若应用代码使用此方法但部署在Tomcat 8.5上,会触发`NoSuchMethodError` 2. **依赖冲突** 应用编译时使用了Servlet 4.0 API库,但运行时Tomcat 8.5仅提供Servlet 3.1实现,导致方法缺失。 --- #### 解决方案 ##### 方案1:升级Tomcat版本(推荐) **步骤:** 1. 下载并安装Tomcat 9.0+([官网下载](https://tomcat.apache.org/download-90.cgi)) 2. 迁移应用: ```bash # 停止旧Tomcat $CATALINA_HOME/bin/shutdown.sh # 备份旧配置(conf/server.xml, conf/context.xml等) cp -r $CATALINA_HOME/conf /backup/tomcat_conf # 部署应用到新Tomcat的webapps目录 cp your_app.war $NEW_TOMCAT_HOME/webapps/ # 启动新Tomcat $NEW_TOMCAT_HOME/bin/startup.sh ``` 3. 验证版本: ```bash $ $NEW_TOMCAT_HOME/bin/version.sh Server version: Apache Tomcat/9.0.xx ``` ##### 方案2:降级应用依赖(兼容Tomcat 8.5) **步骤:** 1. 修改Maven依赖(或Gradle): ```xml <!-- pom.xml --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <!-- 使用3.1.0版本 --> <version>3.1.0</version> <scope>provided</scope> </dependency> ``` 2. 移除代码中对`getHttpServletMapping()`的调用,替换为兼容方案: ```java // 替代方案:通过请求路径解析映射信息 String path = request.getRequestURI(); // 或使用旧版API获取Servlet路径 String servletPath = request.getServletPath(); ``` 3. 清理并重新编译项目: ```bash mvn clean package ``` ##### 方案3:检查配置冲突(辅助措施) 1. 确保`conf/web.xml`中无重复Servlet映射(参考引用[2]): ```xml <servlet-mapping> <servlet-name>your_servlet</servlet-name> <!-- 检查URL模式唯一性 --> <url-pattern>/unique_path/*</url-pattern> </servlet-mapping> ``` 2. 更新`conf/context.xml`启用自动重载(参考引用[3]): ```xml <Context reloadable="true"> ``` --- #### 验证步骤 1. 部署后检查Tomcat日志: ```bash tail -f $CATALINA_HOME/logs/catalina.out ``` 2. 确认无以下错误: ``` java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getHttpServletMapping() ``` --- ### 相关问题 1. 如何检查当前Tomcat支持的Servlet规范版本? 2. 升级Tomcat 9时如何避免应用兼容性问题? 3. Servlet 4.0相对于3.1有哪些主要新特性? [^1]: 配置修改参考Tomcat官方文档 [^2]: Servlet映射冲突解决方案 [^3]: Tomcat更新日志中的配置项说明
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值