【问题标题】:Spring Boot - Error Controller to handle either JSON or HTMLSpring Boot - 处理 JSON 或 HTML 的错误控制器
【发布时间】:2015-06-24 13:58:33
【问题描述】:

我有一个 Spring Boot 应用程序。

我有一个自定义错误控制器,它使用ErrorPage 映射映射到。映射主要基于 HTTP 状态代码,通常只是适当地呈现 HTML 视图。

比如我的映射:

@Configuration
class ErrorConfiguration implements EmbeddedServletContainerCustomizer {

  @Override public void customize( ConfigurableEmbeddedServletContainer container ) {
      container.addErrorPages( new ErrorPage( HttpStatus.NOT_FOUND, "/error/404.html" ) )
  }

还有我的错误控制器:

@Controller
@RequestMapping
public class ErrorController {

    @RequestMapping( value = "/error/404.html" )
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    public String pageNotFound( HttpServletRequest request ) {
        "errors/404"
    }

这很好 - 如果我只是输入一个随机的不存在的 URL,那么它会呈现 404 页面。

现在,我想要我网站的一部分,比如说/api/..,它专门用于我的 JSON api,以将错误作为 JSON 提供,所以如果我在 /api/.. 下输入一个随机不存在的 URL,那么它返回 404 JSON 响应。

是否有任何标准/最佳方法可以做到这一点?我尝试的一个想法是有一个@ControllerAdvice 专门捕获我定义并返回 JSON 的一类自定义 API 异常,并在我的标准 ErrorController 检查 URL 并在该 API URL 空间下抛出一个适当的 API 异常(但是这不起作用,因为无法调用 ExceptionHandler 方法,因为它与原始控制器方法的返回类型不同)。

这件事已经解决了吗?

【问题讨论】:

  • 您能否详细说明您的最后陈述?不清楚您所说的 could not be invoked because it is a different return type 是什么意思。
  • 感谢@zeroflagL - 我应该添加更多细节 - 我现在不在代码中,但是当我回来时会添加更多细节......这是我在测试时看到的更多观察到的行为,但并不详尽。。另一种可能性是,因为抛出代码在 ErrorController 中(所以已经在 springs 错误处理过程中),ControllerAdvice 的工作方式不同

标签: java spring spring-mvc spring-boot


【解决方案1】:

问题是我自己的错。我试图弄清楚为什么我的@ExceptionHandler 无法捕获我的异常并返回 JSON - 正如我在问题末尾所建议的那样,我认为由于返回类型冲突而遇到了问题 - 这是不正确的。

我试图让我的异常处理程序返回 JSON 的错误是:

  "exception": "org.springframework.web.HttpMediaTypeNotAcceptableException",
  "message": "Could not find acceptable representation"

我做了一些更多的挖掘/实验以试图缩小问题范围(认为问题是因为我在 Spring 错误处理流程和导致问题的 ErrorController 中),但是问题只是因为 Spring 所做的内容协商。

因为我在 web.xml 中的 errorPage 映射映射到 /error/404.html,所以 Spring 使用后缀来解析适当的视图 - 所以当我尝试返回 json 时它失败了。

我已经能够通过将我的 web.xml 更改为 /error/404 或关闭内容协商后缀选项来解决此问题。

【讨论】:

    【解决方案2】:

    现在,我想要我网站的一部分,比如说 /api/.. 是专用的 到我的 JSON api 以将错误作为 JSON 提供,所以如果我输入随机 /api/.. 下的 URL 不存在,则返回 404 JSON 响应。

    是否有任何标准/最佳方法可以做到这一点?我尝试过的一个想法是 有一个 @ControllerAdvice 专门捕获了一个自定义类 我定义并返回 JSON 的 API 异常,在我的标准中 ErrorController 检查 URL 并抛出适当的 API 如果在该 API URL 空间下出现异常(但这不起作用,因为 无法调用 ExceptionHandler 方法,因为它是 与原始控制器方法不同的返回类型)。

    我认为您需要重新考虑您要在这里做什么。根据HTTP响应码here

    404 或 Not Found 错误消息是 HTTP 标准响应代码 表明客户端能够与给定的通信 服务器,但服务器找不到请求的内容。

    因此,在输入随机 URL 时,您可能不想一直抛出 404。如果你试图处理一个错误的请求,你可以这样做

    @ControllerAdvice
    public class GlobalExceptionHandlerController {   
    
        @ExceptionHandler(NoHandlerFoundException.class)
        @ResponseStatus(value = HttpStatus.BAD_REQUEST)
        @ResponseBody
        public ResponseEntity<ErrorResponse> noRequestHandlerFoundExceptionHandler(NoHandlerFoundException e) {
            log.debug("noRequestHandlerFound: stacktrace={}", ExceptionUtils.getStackTrace(e));
    
            String errorCode = "400 - Bad Request";
            String errorMsg = "Requested URL doesn't exist";
    
            return new ResponseEntity<>(new ErrorResponse(errorCode, errorMsg), HttpStatus.BAD_REQUEST);
        }
    }
    

    构建满足您需求的ResponseEntity

    【讨论】:

    • 我很高兴我应该对不存在的 URL 进行 404 处理(同意如果它是无效/语法上非法的 URL,我会对其进行 400 处理)。 Spring MVC 的默认行为是 404 任何与映射模式不匹配的请求(假设它与 dispatcherservlet 上下文匹配)。例如,如果您尝试在此处输入随机 URL:stackoverflow.com/aaaa/bbbbbit 404s you.
    猜你喜欢
    • 1970-01-01
    • 2021-01-12
    • 2015-02-01
    • 2016-04-16
    • 2016-11-06
    • 1970-01-01
    • 2012-11-01
    • 2016-01-27
    相关资源
    最近更新 更多