如何区分Apache Tomcat自身与Spring应用返回的404错误?
好问题!完全没必要去解析Tomcat返回的HTML字符串来做区分,那样既脆弱又不优雅,这里有几个更靠谱的方案:
响应头识别法
Tomcat默认返回的404响应会携带特定的Server头部(比如Apache Tomcat/9.0.xx或Apache-Coyote/1.1),而你的应用自身返回404时,可以统一添加自定义响应头(比如X-App-Error: true),或者修改Server头为应用标识。在RestTemplate中捕获HttpClientErrorException.NotFound后,只需检查响应头就能快速区分:try { ResponseEntity<String> response = restTemplate.getForEntity(targetUrl, String.class); } catch (HttpClientErrorException.NotFound e) { HttpHeaders headers = e.getResponseHeaders(); // 判断是否为Tomcat容器返回的404 boolean isTomcat404 = headers.getFirst(HttpHeaders.SERVER) != null && headers.getFirst(HttpHeaders.SERVER).contains("Tomcat"); // 或者通过自定义头判断应用级404 boolean isApp404 = headers.containsKey("X-App-Error"); if (isTomcat404) { // 处理服务未部署等容器级异常 System.out.println("容器级404:目标服务未部署或路径不存在"); } else { // 处理资源不存在等应用级异常 System.out.println("应用级404:请求的资源/账户不存在"); } }统一错误格式校验
让你的Web服务返回的404遵循统一的JSON格式(比如{"errorCode": "RESOURCE_NOT_FOUND", "message": "指定账户不存在"}),而Tomcat默认返回的是HTML内容。捕获异常后,尝试将响应体解析为JSON:如果解析成功,就是应用自身的404;解析失败则是Tomcat容器返回的404:try { ResponseEntity<String> response = restTemplate.getForEntity(targetUrl, String.class); } catch (HttpClientErrorException.NotFound e) { String responseBody = e.getResponseBodyAsString(); ObjectMapper objectMapper = new ObjectMapper(); try { // 解析为自定义错误对象 AppError appError = objectMapper.readValue(responseBody, AppError.class); // 解析成功,处理应用级404 System.out.println("应用级404:" + appError.getMessage()); } catch (JsonProcessingException ex) { // 解析失败,说明是Tomcat的HTML 404 System.out.println("容器级404:目标服务未部署"); } } // 自定义应用错误类 static class AppError { private String errorCode; private String message; // getter和setter省略 public String getMessage() { return message; } }自定义Tomcat错误响应(可选)
如果你有权限配置目标Tomcat,可以修改它的错误页面配置,让容器返回的404也输出带标识的JSON格式。比如在Tomcat的web.xml中添加:<error-page> <error-code>404</error-code> <location>/container-404-handler</location> </error-page>然后写一个简单的Servlet或Spring控制器处理
/container-404-handler路径,返回类似{"errorType": "CONTAINER_NOT_FOUND", "message": "服务未部署或路径无效"}的JSON响应。这样就能和应用级404用相同的解析逻辑区分,通过errorType字段判断即可。
注意:解析HTML字符串是最不推荐的方式,因为Tomcat版本更新可能会修改默认错误页面的内容,导致你的判断逻辑失效,稳定性很差。
内容的提问来源于stack exchange,提问作者JCB

