问题
long story short: I'm creating API that is supposed to be 100% REST. I'm trying to overwrite default response for the following case: I've got a method in my @RestController that has @RequestBody as an attribute
@RequestMapping(value = {"register"}, method = RequestMethod.POST, produces = "application/hal+json")
public Resource<User> registerClient(@RequestBody User user, HttpServletRequest request)
and the method is working just fine if I send a proper request. But there is a problem when I don't. When a request has empty body, I get a generic Tomcat error page for status 400 and I need it to send just a string or a JSON object instead.
So far I tried to add Exception Handlers in my RestControllerAdvice for all Spring exceptions from package org.springframework.web.binding, but it didn't work either.
I'm already aware that for some security-related errors one have to create handlers in configuration, but I don't know if this is the case.
Did anyone face similar issues? Is there something I'm missing?
回答1:
The solution was to simply put required = false in RequestBody annotation. After that, I could easily add some logic to throw custom exception and handle it in ControllerAdvice.
@RequestMapping(value = {"register"}, method = RequestMethod.POST, produces = "application/hal+json")
public Resource<User> registerClient(@RequestBody(required = false) User user, HttpServletRequest request){
logger.debug("addClient() requested from {}; registration of user ({})", getClientIp(request), user);
if(user == null){
throw new BadRequestException()
.setErrorCode(ErrorCode.USER_IS_NULL.toString())
.setErrorMessage("Wrong body or no body in reqest");
} (...)
回答2:
Firstly I suggest you to use BindingResult
as a parameter of the POST call and check if it returns an error or not.
@RequestMapping(value = {"register"}, method = RequestMethod.POST, produces = "application/hal+json")
public ResponseEntity<?> registerClient(@RequestBody User user, HttpServletRequest request, BindingResult brs)
if (!brs.hasErrors()) {
// add the new one
return new ResponseEntity<User>(user, HttpStatus.CREATED);
}
return new ResponseEntity<String>(brs.toString(), HttpStatus.BAD_REQUEST);
}
Secondly, the call can throw some of errors, a good practice is to carch them and return them itself or transform them to your own exception object. The advantage is it secures a call of all the update/modify methods (POST, PUT, PATCH)
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ResponseEntity<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
return new ResponseEntity<List<MethodArgumentNotValidException>>(e, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler({HttpMessageNotReadableException.class})
@ResponseBody
public ResponseEntity<?> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
return new ResponseEntity<List<HttpMessageNotReadableException>>(e, HttpStatus.BAD_REQUEST);
}
回答3:
Your control will never reach to your request method under normal circumstances.
If you want a looking good page you can make use of web.xml
and configure it to produce your answer.
<error-page>
<error-code>404</error-code>
<location>/pages/resource-not-found.html</location>
</error-page>
Generally, if you want to go past this 400 problem, you will have to add a few annotiations to your User.java
to avoid any unknown fields while de-serializing.
来源:https://stackoverflow.com/questions/45997775/java-spring-handle-bad-request-response-for-controller-method-with-requestbod