spring rest 处理空请求体(400 Bad Request)
spring rest Handling empty request body (400 Bad Request)
我正在使用 Spring4 开发 RESTful 应用程序。
我想处理 POST 请求不包含正文的情况。
我编写了以下自定义异常处理程序:
@ControllerAdvice
public class MyRestExceptionHandler {
@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<MyErrorResponse> handleJsonMappingException(JsonMappingException ex) {
MyErrorResponse errorResponse = new MyErrorResponse("request has empty body");
return new ResponseEntity<MyErrorResponse>(errorResponse, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Throwable.class)
public ResponseEntity<MyErrorResponse> handleDefaultException(Throwable ex) {
MyErrorResponse errorResponse = new MyErrorResponse(ex);
return new ResponseEntity<MyErrorResponse>(errorResponse, HttpStatus.BAD_REQUEST);
}
}
@RestController
public class ContactRestController{
@RequestMapping(path="/contact", method=RequestMethod.POST)
public void save(@RequestBody ContactDTO contactDto) {...}
}
当它收到没有正文的 POST 时,不会调用这些方法。
反而,
客户端收到 400 BAD REQUEST HTTP 状态和空主体的响应。
有人知道怎么处理吗?
我遇到了类似的问题,但它对我不起作用,因为提供的 component-scan
包不包括我的 @ControllerAdvice
所在的包。
我的 XML 有:
<context:component-scan base-package="com.bandi.rest" />
我的包裹有错字 com.bandi.test.spring.exception
。将其更改为 com.bandi.rest.spring.exception
后,它开始工作了。
@ControllerAdvice
public class SpringRestExceptionHandler {
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public @ResponseBody ResponseEntity<ErrorResponse> handleNoMethodException(HttpServletRequest request,
NoHandlerFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(ex);
errorResponse.setErrorMessage("resource not found with exception");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Throwable.class)
public @ResponseBody ResponseEntity<ErrorResponse> handleDefaultException(Throwable ex) {
ErrorResponse errorResponse = new ErrorResponse(ex);
errorResponse.setErrorMessage("request has empty body or exception occured");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.BAD_REQUEST);
}
}
此外,如果您需要处理未找到您请求的资源的情况(错误 URL),则您必须向调度程序 servlet 添加另一个配置。
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
完整的工作代码可用here
我解决了这个问题
(自定义异常处理程序必须扩展 ResponseEntityExceptionHandler
)。
我的解决方案如下:
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(
HttpMessageNotReadableException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
// paste custom hadling here
}
}
如果您已经有一个用 @ControllerAdvice
注释的 class 并且不想创建新的,您可以使用这段代码:
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<?> handleMissingRequestBody(Exception ex) {
return handle(BAD_REQUEST, ex);
}
它应该与 rvit34 的解决方案具有相同的行为。
就我而言,我需要处理所有具有无效参数的请求。所以我用 ResponseEntityExceptionHandler
扩展了我的 class 并覆盖了方法 handleMissingServletRequestParameter
。您可以在 class ResponseEntityExceptionHandler
中找到自己定义的处理程序
@ControllerAdvice
public class YourExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(Exception.class)
public final ResponseEntity handleAllExceptions(Exception ex) {
// Log and return
}
@Override
public ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
// Do your code here
return new ResponseEntity<>("YOUR REQUEST PARAMS NOT MATCH!");
}
}
我遇到了同样的问题,在花了很多时间调试这个问题后我发现 jackson 没有正确反序列化 ErrorResponse
对象。
这是因为我没有为 ErrorResponse
对象中定义的字段添加 getter 和 setter。我正在使用构造函数初始化字段,但没有为这些字段定义 getter 和 setter。
解决方案:
所以当我从
更新我的 ErrorResponse
对象时
import com.fasterxml.jackson.annotation.JsonRootName;
import java.util.List;
@JsonRootName("error")
public class ErrorResponse {
private String message;
private List<String> details;
public ErrorResponse(String message, List<String> details) {
this.message = message;
this.details = details;
}
}
下一个有 getter 和 setter 的
import com.fasterxml.jackson.annotation.JsonRootName;
import java.util.List;
@JsonRootName("error")
public class ErrorResponse {
private String message;
private List<String> details;
public ErrorResponse(String message, List<String> details) {
this.message = message;
this.details = details;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<String> getDetails() {
return details;
}
public void setDetails(List<String> details) {
this.details = details;
}
}
Jackson 现在正在正确反序列化 ErrorResponse
,我在响应中得到序列化的正文。
override handleExceptionInternal
方法处理所有的异常,所以你不需要重写每个处理方法:
@Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers,
HttpStatus status, WebRequest request) {
MyErrorResponse myErrorResponse = new MyErrorResponse();
MyErrorResponse.setMessage(ex.getMessage());
return new ResponseEntity<>(myErrorResponse, status);
}
在控制器 class 中,我输入了下面的方法,它解决了我的问题。不需要控制器建议或任何其他。只需将 spring 默认异常覆盖为我们的用户异常本身即可解决问题。
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = {MissingServletRequestParameterException.class})
ApiError handleMethodArgumentNotValid(MissingServletRequestParameterException ex) {
return new ApiError(ErrorCode.MISSING_REQUIRED_PARAMS, ex.getMessage());
}
@ControllerAdvice
@ResponseBody
public class ControllerExceptionHandler {
@ExceptionHandler(BadCredentialsException.class)
@ResponseStatus(value = HttpStatus.FORBIDDEN)
public BaseResponseBean badCredentialsException(BadCredentialsException ex, WebRequest request) {
BaseResponseBean responseBean = new BaseResponseBean();
StatusBean status = new StatusBean();
status.setEnErrorMessage(ex.getMessage());
status.setCode(403);
status.setSuccess(false);
responseBean.setStatus(status);
return responseBean;
}
@ExceptionHandler(HttpClientErrorException.BadRequest.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public BaseResponseBean badRequestException(HttpClientErrorException.BadRequest ex, WebRequest request) {
BaseResponseBean responseBean = new BaseResponseBean();
StatusBean status = new StatusBean();
status.setEnErrorMessage(ex.getMessage());
status.setCode(400);
status.setSuccess(false);
responseBean.setStatus(status);
return responseBean;
}
}
我正在使用 Spring4 开发 RESTful 应用程序。 我想处理 POST 请求不包含正文的情况。 我编写了以下自定义异常处理程序:
@ControllerAdvice
public class MyRestExceptionHandler {
@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<MyErrorResponse> handleJsonMappingException(JsonMappingException ex) {
MyErrorResponse errorResponse = new MyErrorResponse("request has empty body");
return new ResponseEntity<MyErrorResponse>(errorResponse, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Throwable.class)
public ResponseEntity<MyErrorResponse> handleDefaultException(Throwable ex) {
MyErrorResponse errorResponse = new MyErrorResponse(ex);
return new ResponseEntity<MyErrorResponse>(errorResponse, HttpStatus.BAD_REQUEST);
}
}
@RestController
public class ContactRestController{
@RequestMapping(path="/contact", method=RequestMethod.POST)
public void save(@RequestBody ContactDTO contactDto) {...}
}
当它收到没有正文的 POST 时,不会调用这些方法。 反而, 客户端收到 400 BAD REQUEST HTTP 状态和空主体的响应。 有人知道怎么处理吗?
我遇到了类似的问题,但它对我不起作用,因为提供的 component-scan
包不包括我的 @ControllerAdvice
所在的包。
我的 XML 有:
<context:component-scan base-package="com.bandi.rest" />
我的包裹有错字 com.bandi.test.spring.exception
。将其更改为 com.bandi.rest.spring.exception
后,它开始工作了。
@ControllerAdvice
public class SpringRestExceptionHandler {
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public @ResponseBody ResponseEntity<ErrorResponse> handleNoMethodException(HttpServletRequest request,
NoHandlerFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(ex);
errorResponse.setErrorMessage("resource not found with exception");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Throwable.class)
public @ResponseBody ResponseEntity<ErrorResponse> handleDefaultException(Throwable ex) {
ErrorResponse errorResponse = new ErrorResponse(ex);
errorResponse.setErrorMessage("request has empty body or exception occured");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.BAD_REQUEST);
}
}
此外,如果您需要处理未找到您请求的资源的情况(错误 URL),则您必须向调度程序 servlet 添加另一个配置。
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
完整的工作代码可用here
我解决了这个问题
(自定义异常处理程序必须扩展 ResponseEntityExceptionHandler
)。
我的解决方案如下:
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(
HttpMessageNotReadableException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
// paste custom hadling here
}
}
如果您已经有一个用 @ControllerAdvice
注释的 class 并且不想创建新的,您可以使用这段代码:
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<?> handleMissingRequestBody(Exception ex) {
return handle(BAD_REQUEST, ex);
}
它应该与 rvit34 的解决方案具有相同的行为。
就我而言,我需要处理所有具有无效参数的请求。所以我用 ResponseEntityExceptionHandler
扩展了我的 class 并覆盖了方法 handleMissingServletRequestParameter
。您可以在 class ResponseEntityExceptionHandler
@ControllerAdvice
public class YourExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(Exception.class)
public final ResponseEntity handleAllExceptions(Exception ex) {
// Log and return
}
@Override
public ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
// Do your code here
return new ResponseEntity<>("YOUR REQUEST PARAMS NOT MATCH!");
}
}
我遇到了同样的问题,在花了很多时间调试这个问题后我发现 jackson 没有正确反序列化 ErrorResponse
对象。
这是因为我没有为 ErrorResponse
对象中定义的字段添加 getter 和 setter。我正在使用构造函数初始化字段,但没有为这些字段定义 getter 和 setter。
解决方案:
所以当我从
更新我的ErrorResponse
对象时
import com.fasterxml.jackson.annotation.JsonRootName;
import java.util.List;
@JsonRootName("error")
public class ErrorResponse {
private String message;
private List<String> details;
public ErrorResponse(String message, List<String> details) {
this.message = message;
this.details = details;
}
}
下一个有 getter 和 setter 的
import com.fasterxml.jackson.annotation.JsonRootName;
import java.util.List;
@JsonRootName("error")
public class ErrorResponse {
private String message;
private List<String> details;
public ErrorResponse(String message, List<String> details) {
this.message = message;
this.details = details;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<String> getDetails() {
return details;
}
public void setDetails(List<String> details) {
this.details = details;
}
}
Jackson 现在正在正确反序列化 ErrorResponse
,我在响应中得到序列化的正文。
override handleExceptionInternal
方法处理所有的异常,所以你不需要重写每个处理方法:
@Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers,
HttpStatus status, WebRequest request) {
MyErrorResponse myErrorResponse = new MyErrorResponse();
MyErrorResponse.setMessage(ex.getMessage());
return new ResponseEntity<>(myErrorResponse, status);
}
在控制器 class 中,我输入了下面的方法,它解决了我的问题。不需要控制器建议或任何其他。只需将 spring 默认异常覆盖为我们的用户异常本身即可解决问题。
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = {MissingServletRequestParameterException.class})
ApiError handleMethodArgumentNotValid(MissingServletRequestParameterException ex) {
return new ApiError(ErrorCode.MISSING_REQUIRED_PARAMS, ex.getMessage());
}
@ControllerAdvice
@ResponseBody
public class ControllerExceptionHandler {
@ExceptionHandler(BadCredentialsException.class)
@ResponseStatus(value = HttpStatus.FORBIDDEN)
public BaseResponseBean badCredentialsException(BadCredentialsException ex, WebRequest request) {
BaseResponseBean responseBean = new BaseResponseBean();
StatusBean status = new StatusBean();
status.setEnErrorMessage(ex.getMessage());
status.setCode(403);
status.setSuccess(false);
responseBean.setStatus(status);
return responseBean;
}
@ExceptionHandler(HttpClientErrorException.BadRequest.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public BaseResponseBean badRequestException(HttpClientErrorException.BadRequest ex, WebRequest request) {
BaseResponseBean responseBean = new BaseResponseBean();
StatusBean status = new StatusBean();
status.setEnErrorMessage(ex.getMessage());
status.setCode(400);
status.setSuccess(false);
responseBean.setStatus(status);
return responseBean;
}
}