如何让Spring Boot仅在HTML请求时返回500.html错误页
问题解决:根据请求类型返回JSON或HTML错误响应
问题背景
需求:
- 使用
curl调用localhost:8080/fail时返回JSON格式异常信息 - 通过浏览器访问该接口时返回
src/main/templates/error/500.html页面
现有配置:
- 已实现标注
@ControllerAdvice的全局异常处理器GeneralExceptionHandler src/main/templates/error/路径下已放置500.html和404.html,其中404页面可正常生效
问题:触发异常时,无论用curl还是浏览器访问,始终返回JSON结果,浏览器无法加载500错误页面。
问题根源
你的@ControllerAdvice全局异常处理器会捕获所有异常并统一返回JSON响应,没有根据请求的Accept头部判断客户端期望的响应格式,覆盖了Spring Boot默认的错误页面渲染逻辑。而404能正常生效是因为它未被你的全局异常处理器捕获,走的是Spring Boot默认错误处理流程。
解决方案
1. 修改全局异常处理器,根据请求类型返回对应响应
将异常处理方法改为根据客户端请求的Accept头,动态返回ModelAndView(HTML页面)或ResponseEntity(JSON):
@ControllerAdvice public class GeneralExceptionHandler { @Autowired private ContentNegotiationManager contentNegotiationManager; @ExceptionHandler(Exception.class) public Object handleGlobalException(Exception ex, HttpServletRequest request) { // 解析请求期望的响应媒体类型 ServletWebRequest webRequest = new ServletWebRequest(request); MediaType targetMediaType = contentNegotiationManager.resolveMediaTypes(webRequest).getFirst(); if (MediaType.TEXT_HTML.isCompatibleWith(targetMediaType)) { // 浏览器请求,返回500错误页面 ModelAndView modelAndView = new ModelAndView("error/500"); modelAndView.addObject("errorMsg", ex.getMessage()); return modelAndView; } else { // 非浏览器请求(如curl),返回JSON异常信息 Map<String, Object> errorResp = new HashMap<>(); errorResp.put("code", HttpStatus.INTERNAL_SERVER_ERROR.value()); errorResp.put("message", ex.getMessage()); return new ResponseEntity<>(errorResp, HttpStatus.INTERNAL_SERVER_ERROR); } } }
注意:确保使用的是@ControllerAdvice而非@RestControllerAdvice,后者默认所有方法返回JSON,无法返回ModelAndView。
2. 配置内容协商策略(可选)
在application.properties中配置Spring MVC的内容协商规则,确保优先根据Accept头判断响应类型:
# 禁用路径扩展名和参数作为内容协商依据 spring.mvc.contentnegotiation.favor-path-extension=false spring.mvc.contentnegotiation.favor-parameter=false # 允许根据Accept头判断响应类型 spring.mvc.contentnegotiation.ignore-accept-header=false # 默认响应类型为JSON spring.mvc.contentnegotiation.default-content-type=application/json
3. 验证测试
- 使用
curl请求:curl localhost:8080/fail,应返回JSON格式错误信息 - 使用浏览器访问
localhost:8080/fail,应渲染500.html页面
内容的提问来源于stack exchange,提问作者Archimedes Trajano
相关产品推荐
相关产品推荐

