news 2026/10/15 5:23:57

Tomcat正常运行却报404?一套从部署到映射的排查方法论

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Tomcat正常运行却报404?一套从部署到映射的排查方法论

1. 先把404这事儿看明白:它到底在说什么

作为一个常年跟Tomcat打交道的人,404应该是我见过最多的错误之一,没有“之一”我甚至想说就是它。很多新手一看到浏览器里那个硕大的 “HTTP Status 404 – Not Found” 就慌了,以为是Tomcat坏了,赶紧重启、重装、换端口,折腾半天问题还在。这其实是你跟Tomcat之间在沟通上出现了偏差——你要的资源它那里没有,或者它压根没收到你的请求。

先说一个最容易被忽略的点:404的英文全称是“Not Found”,它背后有两层含义。第一层是网络层面的,请求根本没到Tomcat这里来,比如端口错了、IP地址错了,这种情况返回的可能不是Tomcat的404页面,而是浏览器的“无法访问此网站”。第二层是应用层面的,请求到了Tomcat,但是Tomcat在自己的部署目录里、在所有已部署的应用里、在每个应用的URL映射表里,都没能找到跟你请求路径匹配的资源。我们这篇文章讨论的所有内容,几乎都集中在第二层。

还有一个经典场景,就是标题里强调的“Tomcat可以正常运行但是报404”。这种情况尤其迷惑人,因为你访问Tomcat首页能打开,Tomcat的管理界面也能打开,说明服务器本身没毛病,但一访问你的项目就404。这种时候问题基本就锁定在“项目部署”和“项目内部路径配置”这两个环节了。

我需要先给这套排查方案定个基调:别一上来就乱试,先把问题分类,再按顺序排查。404问题的根源五花八门,但归纳起来无非就是几大类——项目部署层面的、路径映射层面的、配置文件层面的、静态资源处理层面的。你只要把这几个方向都搞清楚,绝大多数404都能在五分钟之内定位到原因。

这篇文章我会把多年的排查经验整理成一套可复用的方法论,从最常见的部署问题讲到最刁钻的路径映射问题,每一步都会告诉你原理是什么、为什么要这么做、踩过的坑有哪些。适合刚接触Java Web开发、被404折磨到怀疑人生的新手,也适合那些遇到过“Tomcat明明好好的但项目就是404”的进阶开发者拿来当速查手册。

2. 最常见的404原因排查:先从部署和路径下手

2.1 项目压根没部署成功——这是最冤枉的一种404

我见过太多人排错排了两小时,最后发现war包根本没拷进去,或者项目目录根本不在webapps下面。Tomcat启动后会自动扫描webapps目录下的应用,如果你把一个名为“myapp.war”的文件放在别的地方,Tomcat自然找不到它。这时候你访问 http://localhost:8080/myapp/ 得到的必然是404,而且Tomcat日志里不会有任何报错,因为Tomcat根本不认为这个应用存在。

判断项目到底有没有部署成功,最直接的办法是看Tomcat的启动日志。启动Tomcat时,在控制台或者logs/catalina.out里会有一段类似这样的输出:

INFO [main] org.apache.catalina.startup.HostConfig.deployWAR - Deploying web application archive [myapp.war] INFO [main] org.apache.catalina.startup.HostConfig.deployWAR - Deployment of web application archive [myapp.war] has finished in [1,234] ms

如果你在日志里完全找不到自己的项目名,说明Tomcat根本没扫描到它。这时候检查三件事:webapps目录路径是否正确、war包或解压后的应用目录权限是否足够、Tomcat是否配置了别的deploy目录。

还要注意一种很容易踩的坑:Tomcat默认只扫描webapps目录,但有些IDE或者脚本会把项目部署到wtpwebapps、tomcat-tmp之类的目录。你可能在IDE里点了一个“Run on Server”,看起来部署成功了,但实际上项目被放到了一个单独的部署位置。如果这时候你手动去访问webapps下的路径,照样是404。这种情况下,最好借助IDE的控制台输出确认实际部署路径,别想当然。

2.2 访问路径与上下文路径不匹配——这个坑是真的深

就算项目部署成功了,404还是可能出现,而且这一类的坑对新手极其不友好。每个Web应用在Tomcat里都有一个“上下文路径”,俗称Context Path。默认情况下,如果你把一个项目直接放在webapps下并命名为“myapp”,那上下文路径就是/myapp,你必须访问 http://localhost:8080/myapp/xxx 才能找到资源。

但如果你把这个项目改名为“ROOT.war”部署,或者配置了<Context path="" docBase="...">,上下文路径就变成了空字符串,这时候访问 http://localhost:8080/xxx 才能生效。很多人拿到的项目代码可能配置了server.xml里的Context节点,或者项目里带了META-INF/context.xml,这些配置都会影响实际的上下文路径。

判断项目真实的上下文路径有一个非常可靠的方法:看Tomcat的webapps目录下解压出来的文件夹名字。Tomcat默认以文件夹名作为上下文路径。注意还有一个细节:如果webapps下同时存在“myapp.war”和“myapp”这个文件夹,Tomcat优先使用文件夹里的内容,war包反而不会被解压,这时候文件夹里的旧代码可能跟你想象的不一致。

所以当你要访问的URL是http://localhost:8080/myapp/pages/index.jsp,而你的项目文件夹叫“demo”,那Tomcat找不到/myapp这个上下文就自然会404。搞清楚这个逻辑之后,你需要做的就是把访问路径里的项目名改成实际部署名称,或者干脆把项目部署成ROOT应用。

2.3 欢迎页面配置与默认首页的误导

还有一种特别常见的404,发生在你访问http://localhost:8080/myapp/(根路径)的时候。你期望的是进入首页,结果Tomcat给你返回一个404。这种情况往往是欢迎页面没配好。Tomcat查找欢迎页面的顺序是:先找web.xml里的<welcome-file-list>配置,如果项目里没有这个配置,Tomcat会尝试找index.html、index.htm、index.jsp这几个默认文件。

如果你的项目首页叫login.jsp,而web.xml里什么都没配,Tomcat就不知道要展示哪个文件作为默认页。更气人的是,有时候index.jsp存在,但因为它内部又引用了别的资源路径(比如CSS、JS、图片),而这些资源路径写错了,你访问根路径时页面加载出来的效果就像404一样,打开浏览器开发者工具一看,CSS和JS全部标红报404。

因此排查根路径404时,别只盯着有没有index.jsp,还要看看这个页面里引用的静态资源路径是否是相对路径、是否带了错误的上下文前缀。

3. Servlet与映射配置导致的404:老生常谈但永远有人栽

3.1 web.xml中servlet映射的坑

在Spring Boot还没全面普及的年代,web.xml是Java Web应用的标配。只要web.xml里有一处URL映射写错,你访问对应的Servlet路径就是404。这个错误极其隐蔽,因为Tomcat本身能正常启动,项目也能正常加载,甚至日志里都看不出异常,只是你请求的路径没有任何Servlet响应。

web.xml里的Servlet配置长这样:

<servlet> <servlet-name>loginServlet</servlet-name> <servlet-class>com.example.controller.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping>

两个<servlet-name>必须完全一致,大小写都不能错。但更坑的是<url-pattern>的写法,/login表示只有访问http://localhost:8080/myapp/login这个精确路径才会触发这个Servlet。如果你是访问/login.do或者/login/,直接就404了。还有种写法是*.do,这种通配符路径要求你访问的URL必须以.do结尾,比如/user.do。很多从Struts项目转过来的同学已经习惯访问xxx.action,如果web.xml里写的是*.do而不是*.action,那404就是板上钉钉的事。

还有一个容易忽略的点:<url-pattern>里的斜杠是绝对不能省略的。写login不写/login,Tomcat启动时就会报错或直接忽略这个映射,之后你访问/login自然是404。

3.2 注解方式配置Servlet的常见问题

现在用纯Servlet的项目已经多半改用注解了,比如@WebServlet("/login")。这种方式省事,但也带来了新问题。最典型的就是注解里写的路径忘了带前导斜杠,或者用了Tomcat不支持的路径匹配规则。

@WebServlet的urlPatterns参数支持/login、/login/*、*.do这几种写法,但如果你写login——没有斜杠——多数情况下Tomcat会直接报部署异常,整个应用都启动不了。这反而不是404了,是500或者直接就访问不了。

还有一点,某些时候你加了注解,但项目里还残留着旧的web.xml,而且web.xml里配置了metadata-complete="true"。这个属性一旦设为true,Tomcat在部署时会完全忽略注解扫描,直接把你所有@WebServlet全部无视。这时候你访问任何Servlet路径都会404,而且表面上看起来一切正常。这个坑在从老项目迁移到新版本Tomcat时特别容易遇到。

我的建议是,如果项目用了注解方式,就检查web.xml的根元素里是否有metadata-complete属性,有的话优先删掉或改为false。这招曾经帮我解决过一个排查了整整一个下午的“全站404”问题,那感觉真是柳暗花明。

3.3 配置了Filter但路径写错导致404

这个属于进阶一点的坑了。Filter本身不直接产生404,但如果你写的Filter把请求拦截下来并跳转到了另一个不存在的路径,那你看到的就是404。比如Filter里写了request.getRequestDispatcher("/nonexistent.jsp").forward(...),而这个JSP压根不存在,那响应就会变成404。更隐蔽的是Filter映射的<url-pattern>是/*,它拦截了一切请求,如果Filter代码里做了路径判断但逻辑写反了,就会把本该放行的静态资源也拦下来,再forward到一个错误页面,最后表现成整个应用“到处都是404”。

排查这种问题的方法很简单:在浏览器里访问某个404的URL,同时在Tomcat日志里看有没有Filter相关的打印信息。如果你用了自定义Filter且有日志输出,但日志里只看到拦截没看到放行,那问题八成就在Filter的转发逻辑里。

4. “Tomcat能运行但404”深度排查清单

4.1 一步一步确认Tomcat到底在不在正常工作

当Tomcat能启动、能访问首页,但访问你的项目却404的时候,你要按下面的顺序一步步排除。这套顺序不是我随便排的,是根据“从服务器到应用再到代码”的排查逻辑来设计的,能帮你少走很多弯路。

第一步,确认Tomcat真的正常工作。访问 http://localhost:8080/ 能看到Tomcat的默认首页。如果这一步都过不了,那问题就大了,但不属于本次讨论的404范围。如果这一步没问题,说明Tomcat进程、端口、网络都是正常的。

第二步,确认你的项目是否被部署。去webapps目录下看,有没有你的项目文件夹或者war包。有war包的话,看看有没有对应的解压文件夹。如果没有,把war包拷进去,或者在IDE里重新部署。这一步能解决大约四成“Tomcat正常但404”的问题。

第三步,确认访问URL的上下文路径。访问 http://localhost:8080/项目文件夹名/ 看能否打开应用首页。如果你访问的URL和项目文件夹名不一致,就改URL。如果改URL还是404,继续往下一步。

第四步,确认应用内部的路径映射。用最简单的方式验证——直接访问一个明确的静态资源,比如http://localhost:8080/myapp/css/style.css。如果这个文件存在却还是404,说明整个应用内部路径都没被Tomcat识别,问题多半在配置层面。如果这个文件能访问而Servlet不能访问,那问题就锁定在Servlet映射层面了。

第五步,翻日志。Tomcat的logs目录下有各种日志文件,catalina.out是主日志,localhost.log记录具体应用相关的异常。404不一定有异常信息,但如果你部署失败、映射配置错误,大概率会在这里留下线索。这一步是排查利器,很多新手的问题就在于不看日志,全靠瞎猜。

4.2 静态资源404的特殊处理思路

很多人搭了Spring MVC、Spring Boot的项目之后,发现自己写的静态资源全部404。这种情况在纯Servlet的Tomcat项目里也时有发生,但处理逻辑差不多。你需要搞清楚Tomcat处理静态资源的默认Servlet是谁——在Tomcat的conf/web.xml里配置了一个名为default的Servlet,它映射了/、*.html、*.css、*.js等常见的静态资源后缀。

如果你的应用里的web.xml覆盖或者干扰了defaultServlet的映射,静态资源就可能全部404。比如你给某个Servlet配置了<url-pattern>/</url-pattern>,就把根路径的映射全占了,default Servlet对根路径的默认处理全部失效,所有静态资源直接404。这是Struts或者部分MVC框架配置时的一个经典坑。

还有一种情况:项目里用了Spring Security或者拦截器,把静态资源路径拦截了,导致请求根本没到达default Servlet。你自己写Filter或者Interceptor的时候,一定要把/css/*、/js/*、/images/*这类路径排除掉。不然表面上看起来是“静态资源404”,实际上是被你亲手写的代码拦了。

4.3 虚拟目录与多应用部署的404

当你部署了多个应用,或者配置了虚拟目录,404的判断会更加混乱。Tomcat支持在server.xml的<Host>节点下配置多个<Context>,每个Context有独立的path属性。举个例子:

<Host name="localhost" appBase="webapps"> <Context path="/demo" docBase="/opt/myapps/demo" /> </Host>

这个配置表示把物理路径/opt/myapps/demo映射到URL路径/demo。如果你访问http://localhost:8080/demo/返回404,要检查的是/opt/myapps/demo这个目录是否存在、里面有没有可用的Web应用结构(WEB-INF目录必不可少)。还有个常见问题是:docBase指向的目录里套了一层子目录,比如/opt/myapps/demo/build/libs/demo.war,那Tomcat加载的时候可能找不到上下文根。

虚拟目录的好处是能把应用放到webapps之外,但这也意味着你不能用“看一眼webapps”来判断应用是否部署。遇到这种部署方式,第一件事就是先看server.xml里的Context配置到底指向了哪里,别对着webapps干瞪眼。

5. 常见问题速查表与一套顺手的问题排查顺序

5.1 高频404问题对照表

我把这些年见过最多、最典型的404问题整理成一张速查表,方便你遇到问题直接对照。这张表不追求全,但追求“好使”,覆盖了80%以上的日常404场景:

现象特征根本原因快速验证方法解决办法
Tomcat首页能开,访问项目404项目未部署或部署目录错误看webapps下有没有对应项目文件夹重新部署项目,或调整URL上下文路径
访问根路径/myapp/直接404欢迎页面未配置或缺失看web.xml是否有welcome-file-list配置添加欢迎页配置,或访问具体页面确认
Servlet路径全部404,静态资源正常web.xml映射错误或注解失效检查url-pattern写法与metadata-complete修正映射路径,删除metadata-complete
静态资源CSS/JS/图片全部404default Servlet被抢占查看有没有Servlet映射了/路径改用/*保留静态资源处理,或添加资源映射
单独一个页面404,其他页面正常对应文件不存在或路径大小写不对直接确认文件系统里文件名修正文件名或访问路径,注意Linux大小写敏感
某个跳转后的页面404Filter或控制器转发路径错误查看转发路径目标是否存在修正forward路径或添加对应页面
应用刚部署时偶尔404,刷新后恢复目录扫描延迟或war包还没解压完等几秒再刷新耐心等部署完成,或提前解压war包
换服务器后全站404编译版本、目录结构或路径配置不一致对比原服务器部署目录结构调整上下文路径或重新打包部署

这张表你可以截图存起来,或者打印一份贴在工位上。排查404的时候不用背逻辑,直接对照现象查原因,大多数情况一眼就能定位。

5.2 一套顺手的问题排查顺序

如果你不想用速查表,也可以按照我下面给这套顺序来走,它本质上是个决策树,每一步都指向下一步,不会让你在排查中迷路。

第一步,先确认Tomcat本身没问题。访问首页,能打开就继续,打不开就去查端口和启动日志。第二步,确认部署目录里有没有你的项目。没有就部署,有就继续。第三步,确认URL的上下文路径跟项目实际名称一致。不一致就改URL。一致还404就继续。第四步,访问一个静态资源,比如/css/style.css。静态资源能访问,说明应用部署OK,问题在动态映射;静态资源也404,说明整个应用的请求都没被正确处理,重点查web.xml和Filter。第五步,翻日志。查localhost.log、catalina.out,用关键词搜索“Deploying”“Exception”“Error”。

这套流程走完,你大概率已经能解决问题了。如果还搞不定,那肯定是你遇到了某些极冷门的配置——比如Tomcat的conf/server.xml里的全局配置影响了项目部署、权限问题导致war包无法解压、磁盘满了导致写入失败之类的。这时候就不要瞎试了,老老实实看日志,日志里一定会有线索。

6. 实际项目里那些让我印象深刻的404教训

6.1 一个改了3小时结果是个大小写问题的案例

有一回,开发环境一切正常,代码部署到测试服务器后就全站404。排查了很久,最后发现是Linux服务器上目录大小写敏感的问题——本地Windows不区分大小写,代码里访问的是/Login.jsp,文件名实际是login.jsp。Windows上一切正常,一到Linux就全部404。

这个案例想说明的是:404不一定就是配置问题,也可能是运行环境差异。尤其是从Windows部署到Linux的Java Web项目,大小写敏感、文件编码、路径分隔符、权限设置,这些都可能是404的幕后黑手。我个人的习惯是,凡是涉及文件名和URL路径,一律全小写,让线上和本地保持一致,能省掉非常多不必要的麻烦。

6.2 千万别小看日志里的那几行信息

我见过太多人了,遇到404就先重启,重启完没用就开始搜“Tomcat 404怎么解决”,然后在网上看到的答案五花八门,挨个试了一遍还是不行。其实Tomcat的日志里面写得很清楚了,只是你没去读它。

catalina.out里如果出现类似SEVERE: Error deploying web application archive,那就是部署失败。localhost.log里如果出现org.apache.catalina.core.StandardWrapperValve.invoke相关的异常,那就是应用里处理请求时出了错。哪怕日志里没有任何报错,它至少能告诉你Tomcat有没有尝试去加载你的应用。没有加载,就是部署问题;加载了还是404,就是映射问题;映射没错还404,那就是资源本身问题。

顺便分享一个小技巧:启动Tomcat的时候加一个-verbose:class参数,能看到JVM都加载了哪些类。对于排查类路径不对导致的404或500,有奇效。不过要注意,这个参数会让日志膨胀得非常快,定位到问题之后赶紧去掉。

6.3 最后再分享一个小技巧

排查404时,别老在浏览器里凭肉眼观察。用命令行工具curl直接看HTTP状态码和响应头,比浏览器干净得多,不会被缓存、代理、浏览器插件干扰。比如:

curl -I http://localhost:8080/myapp/login

返回的是404还是200,一目了然。如果你想看完整的内容,用curl -v还能看到请求头和服务器的响应头。这些信息对于定位问题非常有帮助。

另外,如果你用的是Spring Boot内嵌Tomcat,很多排查思路其实也能平移过来,只是部署路径变成了spring-boot-autoconfigure自动配置的逻辑;但“检查路径映射、检查静态资源处理、看日志”这套方法论完全一致。技术框架会变,排查思路永远通用。

做开发这些年,我慢慢意识到:404并不是一个“错误”,它更像是一种提示——你告诉服务器你要找什么,服务器在它自己的世界里没找到,仅此而已。理解了这一点,你就能平静地面对它,然后用正确的方法,一步步解决问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 5:23:56

每日AI行业简报制作指南:人工筛选与结构化模板实践

1. 一份“每日AI行业简报”到底在解决什么问题每天早上打开手机&#xff0c;AI相关的信息像潮水一样涌过来&#xff1a;某团队发布了新的多模态模型、某开源社区更新了推理框架、某公司调整了API定价、某研究机构放出一篇关于智能体协作的论文。信息本身不稀缺&#xff0c;稀缺…

作者头像 李华
网站建设 2026/10/15 5:23:35

XGBoost混合模型预测股票价格:网格搜索与离散小波变换实战

简介&#xff1a;一份基于XGBoost混合模型进行股票预测研究的工程硕士学位论文&#xff0c;适合金融数据分析、机器学习及量化交易方向的读者参考。论文从课题背景与国内外研究现状出发&#xff0c;系统梳理股票预测理论基础&#xff0c;深入讲解决策树、CART、GBDT与XGBoost原…

作者头像 李华
网站建设 2026/10/15 5:23:03

省算力新利器 DeepGEMM:从 GEMM 原理到 LLM 推理加速实践

做深度学习训练和推理的朋友应该都有这种感觉&#xff1a;模型规模越堆越大&#xff0c;算力账单也越来越吓人。不管是自己搭卡跑实验&#xff0c;还是在云上租集群&#xff0c;最后发现真正卡脖子的往往不是模型设计&#xff0c;而是底层那层“看不见”的矩阵乘法。最近我花了…

作者头像 李华
网站建设 2026/10/15 5:22:56

手写分块注意力:中间矩阵从 128MB 压到 128KB,输出偏差 1.42e-07

手写分块注意力&#xff1a;中间矩阵从 128MB 压到 128KB&#xff0c;输出偏差 1.42e-07 序列长度 4096、单头、float32&#xff0c;标准写法要先算出一张 40964096 的打分矩阵&#xff0c;占 128 MB&#xff1b;改成分块计算之后&#xff0c;同时在内存里的中间张量只有 128 K…

作者头像 李华
网站建设 2026/10/15 5:22:29

阿里开源DataX支持Oracle update模式:改造oraclewriter实现增量同步

1. 从一个真实的数据同步痛点说起做数据集成这行的朋友&#xff0c;大概率都跟 DataX 打过交道。它是阿里开源的一款异构数据源离线同步工具&#xff0c;主打批量数据搬运&#xff0c;在数据仓库搭建、数据迁移、ETL 流程里出镜率极高。但用久了你会发现一个很尴尬的事&#xf…

作者头像 李华
网站建设 2026/10/15 5:22:17

iOS嵌套滚动实战:手势冲突与边界传递解决方案

1. 嵌套滚动的本质矛盾与场景拆解iOS开发里&#xff0c;ScrollView嵌套ScrollView这件事&#xff0c;几乎每个做内容型App的开发者都会撞上。你有一个横向分页的容器&#xff0c;每个分页里又有一个纵向滚动的列表&#xff1b;或者反过来&#xff0c;外层纵向滚动承载整页内容&…

作者头像 李华