
别慌!这篇文章把Javaweb工程中90%的404坑都挖透了:小到URL多写个斜杠、静态资源(CSS/JS/图片)用了绝对路径,大到WEB-INF目录资源被拦截、Tomcat“上下文路径”配置错误、SpringMVC/Struts2框架路由映射失效……每一个问题都附了step by step的排查流程——比如用浏览器“检查元素”看静态资源请求路径,在Tomcat的server.xml里改上下文路径,甚至用Log4j打印完整请求URL。
不管你是刚入门的新手(怕看不懂配置),还是烦透瞎试的老开发,跟着走不用瞎猜,5分钟就能把404“打回原形”。 咱们直接奔着问题去,一个个解决!
做Javaweb开发的应该都有过这种崩溃瞬间——昨天还好好运行的工程,今天改了几行代码重启后,浏览器突然弹出“HTTP Status 404 – Not Found”。你盯着页面刷新三遍,翻遍Controller的注解、JSP的路径,甚至重启Tomcat,问题却像藏在代码里的“隐形虫”,半点线索都没有。别慌,我把过去3年帮10多个项目排查404的经验全整理了,从最基础的路径错到框架配置坑,再到Tomcat的“隐形”设置,跟着走不用瞎猜,5分钟就能把404“打回原形”。
最常见的404根源:路径与资源访问问题
404的本质其实是“服务器找不到你要的资源”,而80%的情况都出在“路径”上——要么你请求的路径和后端定义的不一致,要么资源的存放位置不对。我先给你掰扯最常踩的两个坑:URL路径错误和静态资源访问失败,都是我帮同事、客户排查过的真实案例。
URL路径错:大小写、斜杠、参数的“小错误”
你肯定遇到过这种情况:后端写了@RequestMapping("/userinfo")
,前端却用/userInfo
访问,结果404——别笑,我去年帮一个做CRM系统的朋友就解决过这个问题。他本地Windows开发时没问题(Windows下Tomcat不区分大小写),上线到Linux服务器就崩了,因为Tomcat默认遵循Servlet规范,对URL大小写敏感。后来他把前端的URL改成小写,问题立刻解决。
除了大小写,斜杠多一个少一个也会坑人。比如后端定义/api/v1/order
,前端写成/api/v1//order
(多了个斜杠),Tomcat会自动合并成一个斜杠,所以能访问;但要是写成/api/v1order
(少了个斜杠),那肯定404——因为路径完全对不上。还有路径参数的问题:比如你要做一个根据ID查用户的接口,后端写/rest/user/{id}
,但前端访问/rest/user/id/123
(多了个id
),这时候服务器会认为你要访问/rest/user/id/123
这个路径,而不是带参数的/rest/user/{id}
,自然返回404。
怎么快速排查?用浏览器的开发者工具看请求URL——打开F12,点“网络”标签,刷新页面,看请求的“URL”列是不是和后端@RequestMapping
的路径完全一致(包括大小写、斜杠、参数占位符)。要是不一致,改对就行;要是一致还404,再往下查。
静态资源访问失败:CSS/JS/图片为什么加载不出来?
你有没有遇到过“页面能打开,但CSS没加载,变成‘裸奔’页面”的情况?这也是404的一种——静态资源没找到。最常见的原因是用了绝对路径,没带应用的“上下文路径”。比如你把CSS文件放在webapp/css
下,前端写/css/style.css
,但你的应用部署在/myapp
路径下(比如Tomcat的webapps里的war包叫myapp.war),这时候浏览器会请求http://localhost:8080/css/style.css
,而实际资源在http://localhost:8080/myapp/css/style.css
,自然404。
解决办法超简单:把绝对路径改成带上下文路径的相对路径。比如用JSP的EL表达式写${pageContext.request.contextPath}/css/style.css
,或者在HTML里用/myapp/css/style.css
(但“myapp”是硬编码,不如EL表达式灵活)。还有一种情况是SpringMVC拦截了静态资源——要是你在SpringMVC的配置里把DispatcherServlet
的url-pattern
设为/
(拦截所有请求),那静态资源请求会被DispatcherServlet接管,但它找不到对应的处理器,就返回404。这时候要在SpringMVC的配置文件里加一句,让DispatcherServlet把静态资源请求转发给Tomcat的默认Servlet处理,亲测有效。
框架与服务器配置:藏在代码背后的“隐形坑”
要是路径和资源都没问题,那问题大概率出在框架路由或服务器配置上——比如SpringMVC没扫描到Controller,或者Tomcat的上下文路径配错了。这些坑更“隐形”,但只要摸透原理,一样能快速解决。
SpringMVC/Struts2的路由坑: Controller没被扫描到
我之前帮一个刚入门的开发者排查过问题:他写了个UserController
,加了@RestController
和@RequestMapping("/user")
,但访问/user/list
时404。我看了他的Spring配置文件,发现@ComponentScan
的basePackage
只写了com.example.service
,没包含com.example.controller
——Spring没扫描到Controller,自然不会映射URL。后来他把basePackage
改成com.example
(包含controller包),重启后日志里出现“Mapped URL path [/user/list] onto handler [com.example.controller.UserController#list()]”,问题解决。
还有Struts2的坑:要是你在struts.xml
里把namespace
设为/user
,action
的name
设为login
,那访问路径应该是/user/login.action
(默认后缀是.action
)。要是你写成/login.action
,Struts2会在根namespace(/
)下找login
的action,找不到就返回404。解决办法很简单:检查struts.xml
的namespace
和action
的name
,确保访问路径是“namespace+action name+后缀”。
Tomcat的“隐形”设置:上下文路径与默认Servlet
Tomcat的配置错也是404的重灾区,尤其是上下文路径(Context Path)——这是应用的“访问入口”,比如你部署了一个叫myapp.war
的应用,Tomcat默认会把上下文路径设为/myapp
,所以访问路径是http://localhost:8080/myapp
。要是你手动把server.xml
里的Context
元素path
属性改成/shop
,那访问路径就得改成http://localhost:8080/shop
,不然肯定404。我之前遇到过一个运维把path
设成了/mall
,但开发把前端的请求路径写成/myapp
,结果线上全是404,最后改回/myapp
才解决。
还有一个容易忽略的点:默认Servlet被覆盖。Tomcat的conf/web.xml
里有个默认Servlet,url-pattern
是/
,负责处理静态资源(比如CSS、JS)。要是你在项目的web.xml
里自定义了一个Servlet,url-pattern
也是/
,就会覆盖默认Servlet——这时候静态资源请求会被自定义Servlet接管,但它处理不了,就返回404。解决办法有两个:要么把自定义Servlet的url-pattern
改成更具体的(比如/api/*
),要么在SpringMVC里加,让DispatcherServlet把静态资源请求转发给默认Servlet。
常见场景 | 错误原因 | 解决步骤 | 验证方法 |
---|---|---|---|
访问接口404 | URL大小写与后端不一致 | 修改前端URL为与后端@RequestMapping一致的大小写 | 用Postman发送正确大小写的URL,看是否返回200 |
静态图片加载失败 | 使用了绝对路径,未包含上下文路径 | 将路径改为“${pageContext.request.contextPath}/images/logo.png” | 查看浏览器开发者工具的请求URL,是否包含上下文路径 |
SpringMVC接口404 | Controller未被扫描到 | 检查@ComponentScan的basePackage是否包含Controller所在包 | 启动项目时看日志,是否有“Mapped URL path [/xxx] onto handler”的提示 |
Tomcat部署后404 | 上下文路径配置错误 | 修改server.xml中Context的path属性为正确路径 | 访问“http://localhost:8080/正确路径”,看是否能打开首页 |
其实404没那么可怕,本质就是“请求的资源不在服务器上”——要么路径错,要么资源没放对,要么配置没配好。你按我给的步骤排查:先查URL路径(用开发者工具看请求URL),再查静态资源(看路径是不是带上下文),再查框架配置(看Controller有没有被扫描),最后查Tomcat设置(看上下文路径对不对)。要是还解决不了,或者遇到了更奇怪的场景——比如“同一个接口有时候404有时候正常”“线上能跑本地不行”,欢迎在评论区留具体情况,我帮你一起揪出问题~
为什么本地Windows开发没问题,上线Linux服务器就报404?
这大概率是URL大小写的问题。Windows系统下Tomcat不区分URL大小写,但Linux服务器遵循Servlet规范,对URL大小写敏感。比如后端定义的是@RequestMapping(“/userinfo”),前端用”/userInfo”访问,Windows下能正常响应,Linux下就会因为路径不匹配返回404。
解决办法很简单,把前端请求的URL和后端定义的路径统一大小写就行,比如都改成小写,或者都用驼峰,但一定要保持一致。
静态资源(CSS/JS/图片)加载不出来,提示404怎么办?
最常见的原因是用了绝对路径没带应用的“上下文路径”。比如你的应用部署在”/myapp”下,静态资源放在”webapp/css”里,前端写”/css/style.css”,浏览器会请求”http://localhost:8080/css/style.css”,但实际资源在”http://localhost:8080/myapp/css/style.css”,自然404。
解决方法是把路径改成带上下文路径的相对路径,比如用JSP的EL表达式写”${pageContext.request.contextPath}/css/style.css”。如果是SpringMVC拦截了静态资源,还要在配置文件里加””,让DispatcherServlet把静态资源请求转发给Tomcat的默认Servlet处理。
SpringMVC写了Controller,访问接口还是404,怎么回事?
先检查Controller有没有被Spring扫描到。比如你用了@ComponentScan注解,但basePackage只写了”com.example.service”,没包含Controller所在的”com.example.controller”包,Spring就不会加载这个Controller,自然访问不到接口。
可以启动项目时看日志,如果有“Mapped URL path [/xxx] onto handler [com.example.controller.XXXController#xxx()]”的提示,说明Controller被扫描到了;如果没有,就得修改@ComponentScan的basePackage,比如改成”com.example”(包含controller包)。
Tomcat部署工程后,访问首页就404,怎么排查?
先看应用的“上下文路径”对不对。Tomcat默认会把war包的名字作为上下文路径,比如你的war包叫”myapp.war”,部署后访问路径得是”http://localhost:8080/myapp”。如果手动改了server.xml里Context元素的path属性,比如改成”/shop”,那访问路径就得是”http://localhost:8080/shop”。
检查工程的WEB-INF/web.xml里有没有配置欢迎页,比如里有没有”index.jsp”或”index.html”,要是没配置,Tomcat找不到默认首页也会报404。
WEB-INF目录里的JSP直接访问报404,正常吗?
这是正常的,因为WEB-INF是Tomcat的安全目录,里面的资源不能通过浏览器直接访问,目的是防止用户直接获取敏感文件(比如配置文件、JSP源码)。
要是想访问WEB-INF里的JSP,得通过Servlet或Controller转发。比如在Controller里写一个方法,用RequestDispatcher的forward方法把请求转发到WEB-INF下的JSP,像这样:request.getRequestDispatcher(“/WEB-INF/views/index.jsp”).forward(request, response),这样浏览器就能通过访问Controller的路径间接访问JSP了。