问题的起点
访问 http://localhost:8080 看到一个空白页或者:
HTTP Status 404 – Not Found
The origin server did not find a current representation
for the target resource or is not willing to disclose that one exists.
这说明 Tomcat 启动成功了(端口监听正常),但它找不到你要的资源。404 在 Tomcat 中有多种可能性,逐层排查比瞎改配置高效得多。
Tomcat 的目录结构决定了访问路径
理解 Tomcat 的目录结构是排查 404 的基础:
tomcat/
├── bin/ # 启动脚本(catalina.bat/sh)
├── conf/
│ ├── server.xml # 核心配置:端口、Host、Context
│ └── web.xml # 全局 web.xml,所有应用继承
├── webapps/ # WAR 包和展开目录放这里 ★
│ ├── ROOT/ # 默认应用(路径 = /)
│ ├── myapp/ # 应用 myapp(路径 = /myapp)
│ └── myapp.war # WAR 包,启动时自动展开
├── logs/ # 日志
├── work/ # JSP 编译后的 Servlet 源码
└── temp/
访问路径的映射规则
URL: http://localhost:8080/myapp/user/list.jsp
│ │
│ └── Web 应用内的资源路径
│ (相对于 WebContent/src/main/webapp)
└── Context Path(等于目录名或 WAR 名,ROOT 例外)
几个容易踩坑的点:
- Context Path 不是项目名:Context Path 默认等于 WAR 文件名或目录名,但可以通过
META-INF/context.xml或server.xml中的<Context path="/xxx">覆盖 - ROOT 是特例:放到
webapps/ROOT/下的应用,Context Path 是/,访问http://localhost:8080/就行 - IDEA/Eclipse 的部署路径可能不同:IDE 可能把应用部署到临时目录而不是
webapps/,路径映射会变
404 的五种根因
1. Context Path 不对
你的资源在: webapps/myapp/index.jsp
你访问的: http://localhost:8080/index.jsp ← 少了一层 /myapp
正确的: http://localhost:8080/myapp/index.jsp ✓
排查:
# 看 Tomcat 日志确认部署了哪些应用
tail -f tomcat/logs/catalina.out | grep "Deploy"
# 或者访问 Manager 应用(需要配置用户)
http://localhost:8080/manager/html
2. 资源在 WEB-INF 目录下
WebContent/
├── index.jsp ← 可以直接访问: /myapp/index.jsp
└── WEB-INF/
├── web.xml
├── classes/ ← Servlet class 文件
├── lib/ ← jar 包
└── secret.jsp ← 无法直接访问!/myapp/WEB-INF/secret.jsp → 404
WEB-INF 下的内容是受保护的——这是 Servlet 规范的设计。客户端无法直接通过 URL 访问 WEB-INF 下的任何文件。只有 Servlet 的 RequestDispatcher 可以转发到 WEB-INF 下的资源。
// 这样是可以的——服务端转发
request.getRequestDispatcher("/WEB-INF/view/result.jsp").forward(request, response);
// 客户端直接访问就是 404
// http://localhost:8080/myapp/WEB-INF/view/result.jsp → 404
这是安全设计,不是 bug。把 JSP 放到 WebContent/(或 src/main/webapp/)下而不是 WEB-INF/ 下。
3. class 文件找不到(输出目录配置错误)
这个坑主要出现在 Eclipse 中。Eclipse 默认把编译后的 class 文件输出到 build/classes/,但 Tomcat 期望类文件在 WEB-INF/classes/ 下。
期望的目录结构:
WEB-INF/classes/com/example/MyServlet.class ← Tomcat 从这里找
Eclipse 默认输出:
build/classes/com/example/MyServlet.class ← Eclipse 编译到这里
修复:
项目右键 → Build Path → Configure Build Path
→ Source 标签页
→ Default output folder: 改成 WEB-INF/classes
IDEA 通常不会遇到这个问题——它默认输出到 out/production/,部署时自动拷贝到正确位置。
4. JSP 在子目录中,路径层级不对
WebContent/
└── jsp/
└── user/
└── list.jsp
访问路径: /myapp/jsp/user/list.jsp
│ │ │
│ │ └── JSP 文件名
│ └── 子目录
└── 顶层文件夹
每一个子目录对应 URL 中的一个路径段。
5. web.xml 的 url-pattern 配置错误
Servlet 的 URL 映射在 web.xml 或 @WebServlet 注解中定义:
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/user</url-pattern> ← 注意:不是 /UserServlet
</servlet-mapping>
访问 /myapp/UserServlet → 404。应该访问 /myapp/user。
@WebServlet 注解的情况:
@WebServlet("/user") // 访问 /myapp/user
@WebServlet("/user/*") // 访问 /myapp/user/xxx 都走这个 Servlet
@WebServlet("*.do") // 访问 /myapp/anything.do
url-pattern 匹配规则:
- 精确匹配
/user:完全一致才命中 - 路径匹配
/user/*:前缀匹配 - 扩展名匹配
*.jsp:后缀匹配 - 默认匹配
/:兜底,处理所有未匹配的请求
匹配优先级:精确 > 路径 > 扩展名 > 默认。
排查 404 的系统化流程
┌─────────────────────────┐
│ Tomcat 启动成功了吗? │
│ 检查 catalina.out │
└────────────┬──────────────┘
│
┌────────────▼──────────────┐
│ 应用部署成功了吗? │
│ 看 Manager 或 deploy 日志 │
└────────────┬──────────────┘
│
┌────────────▼──────────────┐
│ 访问的 URL 路径是否正确? │
│ Context Path + 资源路径 │
└────────────┬──────────────┘
│
┌────────────▼──────────────┐
│ 资源在 WEB-INF 之外吗? │
│ JSP 必须在 WebContent 下 │
└────────────┬──────────────┘
│
┌────────────▼──────────────┐
│ class 文件在正确位置吗? │
│ WEB-INF/classes/ │
└────────────┬──────────────┘
│
┌────────────▼──────────────┐
│ url-pattern 映射正确吗? │
│ 检查 web.xml / @WebServlet│
└────────────────────────────┘
附加:为什么 Eclipse/IDEA 中 Tomcat 可能不更新
有时候你改了代码,重启 Tomcat 但还是老结果——不是 404,而是”改的代码没生效”。
原因:IDE 没有把修改后的 class 自动部署到 Tomcat。解决:
- IDEA:手动 Build → Build Artifacts → Rebuild
- Eclipse:Project → Clean,或者勾选 “Automatically publish when resources change”
总结
- 404 不是玄学——是路径映射、目录结构、资源可见性三者之一出了问题
- WEB-INF 下的内容客户端无法访问,这是 Servlet 规范的安全设计
- IDE 部署路径和 Tomcat 期望路径不一致时(Eclipse build/classes 问题),类加载失败但报 404 而非 ClassNotFound
- Context Path 默认 = WAR 名/目录名,ROOT 是特例
- url-pattern 的 4 种匹配规则有严格优先级
☕ 如果这篇文章对你有帮助
欢迎请我喝杯咖啡支持一下
评论