Java Web应用中图片404错误的自定义处理方案问询
好的,针对你提出的需求——给图片资源的404错误做差异化处理,同时能在返回响应前检查请求头,这里有两种实用的方案,都是Java Web生态里比较成熟的实现方式:
针对图片404错误的自定义处理方案
方案一:用自定义Filter精准拦截图片请求
这种方式相当于给所有图片请求加了个「前置检查器」,能在请求到达目标资源前后灵活判断状态,完全不影响其他资源的404处理逻辑:
1. 编写自定义Filter类
我们先写一个Filter,专门拦截图片后缀的请求,同时通过响应包装器捕获状态码,再结合请求头做处理:
import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Set; // 直接用注解指定要拦截的图片后缀 @WebFilter(urlPatterns = {"*.jpg", "*.jpeg", "*.png", "*.gif", "*.webp"}) public class Image404Filter implements Filter { // 可根据业务需求扩展支持的图片格式 private static final Set<String> IMAGE_EXTENSIONS = Set.of("jpg", "jpeg", "png", "gif", "webp"); @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化逻辑(比如加载配置,不需要可以留空) } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; // 1. 检查请求头(示例:判断客户端是否接受HTML格式响应) String acceptHeader = req.getHeader("Accept"); boolean acceptsHtml = acceptHeader != null && acceptHeader.contains("text/html"); // 2. 用响应包装器捕获请求的状态码,判断资源是否存在 StatusCaptureResponseWrapper responseWrapper = new StatusCaptureResponseWrapper(resp); RequestDispatcher dispatcher = req.getRequestDispatcher(req.getRequestURI()); dispatcher.include(req, responseWrapper); if (responseWrapper.getStatus() == HttpServletResponse.SC_NOT_FOUND) { // 3. 图片资源不存在,根据请求头返回不同内容 if (acceptsHtml) { // 给浏览器返回简洁的占位提示 resp.setContentType("text/html"); resp.getWriter().write("<div style='width:100px;height:100px;background:#eee;display:flex;align-items:center;justify-content:center;color:#666;'>图片不存在</div>"); } else { // 给API/爬虫等返回纯文本404提示 resp.setStatus(HttpServletResponse.SC_NOT_FOUND); resp.setContentType("text/plain"); resp.getWriter().write("Image not found"); } } else { // 图片资源存在,正常返回内容 chain.doFilter(req, resp); } } @Override public void destroy() { // 销毁逻辑(不需要可以留空) } // 自定义响应包装器,用来捕获容器返回的状态码 private static class StatusCaptureResponseWrapper extends HttpServletResponseWrapper { private int status = HttpServletResponse.SC_OK; public StatusCaptureResponseWrapper(HttpServletResponse response) { super(response); } @Override public void setStatus(int sc) { super.setStatus(sc); this.status = sc; } @Override public void sendError(int sc) throws IOException { super.sendError(sc); this.status = sc; } @Override public void sendError(int sc, String msg) throws IOException { super.sendError(sc, msg); this.status = sc; } public int getStatus() { return status; } } }
2. 配置说明(可选)
如果你的项目不支持Servlet 3.0+注解,就在web.xml里手动配置Filter:
<filter> <filter-name>Image404Filter</filter-name> <filter-class>com.your.package.Image404Filter</filter-class> </filter> <filter-mapping> <filter-name>Image404Filter</filter-name> <url-pattern>*.jpg</url-pattern> <url-pattern>*.jpeg</url-pattern> <url-pattern>*.png</url-pattern> <url-pattern>*.gif</url-pattern> <url-pattern>*.webp</url-pattern> </filter-mapping>
3. 保留全局404配置
你原来的全局404配置可以继续保留,非图片资源的404依然会跳转到error.xhtml:
<error-page> <error-code>404</error-code> <location>/error.xhtml</location> </error-page>
方案二:用自定义错误Servlet统一处理404
这种方式把所有404错误都导向一个专门的Servlet,在Servlet里区分图片请求和普通请求,逻辑更集中:
1. 编写自定义错误处理Servlet
import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Set; @WebServlet("/custom-error-handler") public class CustomErrorHandlerServlet extends HttpServlet { private static final Set<String> IMAGE_EXTENSIONS = Set.of("jpg", "jpeg", "png", "gif", "webp"); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { // 获取容器传递的错误状态码 Integer statusCode = (Integer) req.getAttribute("javax.servlet.error.status_code"); if (statusCode == null || statusCode != HttpServletResponse.SC_NOT_FOUND) { // 非404错误,转发到全局错误页面 try { req.getRequestDispatcher("/error.xhtml").forward(req, resp); return; } catch (Exception e) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } } // 判断当前请求是否是图片资源 String requestUri = (String) req.getAttribute("javax.servlet.error.request_uri"); boolean isImageRequest = false; if (requestUri != null) { String extension = requestUri.substring(requestUri.lastIndexOf(".") + 1).toLowerCase(); isImageRequest = IMAGE_EXTENSIONS.contains(extension); } // 检查请求头,决定返回内容 String acceptHeader = req.getHeader("Accept"); boolean acceptsHtml = acceptHeader != null && acceptHeader.contains("text/html"); if (isImageRequest) { // 处理图片404 if (acceptsHtml) { resp.setContentType("text/html"); resp.getWriter().write("<div style='width:120px;height:120px;background:#f5f5f5;border:1px dashed #ccc;display:flex;align-items:center;justify-content:center;color:#999;font-size:14px;'>图片已失效</div>"); } else { resp.setStatus(HttpServletResponse.SC_NOT_FOUND); resp.setContentType("text/plain"); resp.getWriter().write("404 - Image Not Found"); } } else { // 非图片404,转发到原有error.xhtml try { req.getRequestDispatcher("/error.xhtml").forward(req, resp); } catch (Exception e) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } } }
2. 修改web.xml的错误页面配置
把原来的全局404配置指向这个自定义Servlet:
<error-page> <error-code>404</error-code> <location>/custom-error-handler</location> </error-page>
方案对比
- Filter方案:更轻量化,只拦截图片请求,不干扰其他资源的错误处理流程,适合需要精准控制的场景。
- 自定义错误Servlet方案:逻辑更集中,能统一管理所有404错误,适合需要对错误做全局统一处理的项目。
你可以根据自己的项目架构和需求选择合适的方案,两种方式都能完美满足你检查请求头、差异化处理图片404的需求。
内容的提问来源于stack exchange,提问作者Steven De Groote
相关产品推荐
相关产品推荐

