7.3.1 将异常映射为 HTTP 状态码

在默认情况下,Spring 会将自身的一些异常自动转换为合适的状态码。表 7.1 列出了这些映射关系。

Spring 异常

HTTP 状态码

BindException

400 - Bad Request

ConversionNotSupportedException

500 - Internal Server Error

HttpMediaTypeNotAcceptableException

406 - Not Acceptable

HttpMediaTypeNotSupportedException

415 - Unsupported Media Type

HttpMessageNotReadableException

400 - Bad Request

HttpMessageNotWritableException

500 - Internal Server Error

HttpRequestMethodNotSupportedException

405 - Method Not Allowed

MethodArgumentNotValidException

400 - Bad Request

MissingServletRequestParameterException

400 - Bad Request

MissingServletRequestPartException

400 - Bad Request

NoSuchRequestHandlingMethodException

404 - Not Found

TypeMismatchException

400 - Bad Request

表 7.1 中的异常一般会由 Spring 自身抛出,作为 DispatcherServlet 处理过程中或执行校验时出现问题的结果。例如,如果 DispatcherServlet 无法找到适合处理请求的控制器方法,那么将会抛出 NoSuchRequestHandlingMethod-Exception 异常,最终的结果就是产生 404 状态码的响应(Not Found)。

尽管这些内置的映射是很有用的,但是对于应用所抛出的异常它们就无能为力了。幸好,Spring 提供了一种机制,能够通过 @ResponseStatus 注解将异常映射为 HTTP 状态码。

为了阐述这项功能,请参考 SpittleController 中如下的请求处理方法,它可能会产生 HTTP 404 状态(但目前还没有实现):

@RequestMapping(value="/{spittleId}", method=RequestMethod.GET)
public String spittle(
    @PathVariable("spittleId") long spittleId, 
    Model model) {
  Spittle spittle = spittleRepository.findOne(spittleId);
  if (spittle == null) {
    throw new SpittleNotFoundException();
  }
  model.addAttribute(spittle);
  return "spittle";
}

在这里,会从 SpittleRepository 中,通过 ID 检索 Spittle 对象。如果 findOne() 方法能够返回 Spittle 对象的话,那么会将 Spittle 放到模型中,然后名为 spittle 的视图会负责将其渲染到响应之中。但是如果 findOne() 方法返回 null 的话,那么将会抛出 SpittleNotFoundException 异常。现在 SpittleNot-FoundException 就是一个简单的非检查型异常,如下所示:

package spittr.web;

public class SpittleNotFoundException extends RuntimeException {
}

如果调用 spittle() 方法来处理请求,并且给定 ID 获取到的结果为空,那么 SpittleNotFoundException(默认)将会产生 500 状态码(Internal Server Error)的响应。实际上,如果出现任何没有映射的异常,响应都会带有 500 状态码,但是,我们可以通过映射 SpittleNotFoundException 对这种默认行为进行变更。

当抛出 SpittleNotFoundException 异常时,这是一种请求资源没有找到的场景。如果资源没有找到的话,HTTP 状态码 404 是最为精确的响应状态码。所以,我们要使用 @ResponseStatus 注解将 SpittleNotFoundException 映射为 HTTP 状态码 404。

package spittr.web;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Spittle Not Found")
public class SpittleNotFoundException extends RuntimeException {
}

在引入 @ResponseStatus 注解之后,如果控制器方法抛出 SpittleNotFound-Exception 异常的话,响应将会具有 404 状态码,这是因为 Spittle Not Found。

Last updated