我在控制器中有一个方法,例如有参数
@RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void post(@RequestHeader("ETag") int etag)
如果请求中没有ETag标头 - 客户端获得400(BAD_REQUEST),这不是任何信息。我需要以某种方式处理此异常并将我自己的异常发送到客户端(我为此目的使用JSON)。我知道我可以通过@ExceptionHandler拦截异常,但在这种情况下,所有HTTP 400请求都将被处理,但我希望在标题中缺少ETag。有任何想法吗?
您应该使用@ExceptionHandler方法查看是否存在ETag标头并采取适当的操作:
@ExceptionHandler(UnsatisfiedServletRequestParameterException.class)
public onErr400(@RequestHeader(value="ETag", required=false) String ETag,
UnsatisfiedServletRequestParameterException ex) {
if(ETag == null) {
// Ok the problem was ETag Header : give your informational message
} else {
// It is another error 400 : simply say request is incorrect or use ex
}
}
有两种方法可以实现您的目标
首先使用@RequestHeader
和required
false
@RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void post(@RequestHeader(value="ETag", required=false) String ETag) {
if(ETag == null) {
// Your JSON Error Handling
} else {
// Your Processing
}
}
第二次使用HttpServletRequest
而不是@RequestHeader
@RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void post(HttpServletRequest request) {
String ETag = request.getHeader("ETag");
if(ETag == null) {
// Your JSON Error Handling
} else {
// Your Processing
}
}
使用注释@ExceptionHandler编写一个方法并使用ServletRequestBindingException.class,因为如果缺少标题则抛出此异常
例如 :
@ExceptionHandler(ServletRequestBindingException.class)
public ResponseEntity<ResponseObject> handleHeaderError(){
ResponseObject responseObject=new ResponseObject();
responseObject.setStatus(Constants.ResponseStatus.FAILURE.getStatus());
responseObject.setMessage(header_missing_message);
ResponseEntity<ResponseObject> responseEntity=new ResponseEntity<ResponseObject>(responseObject, HttpStatus.BAD_REQUEST);
return responseEntity;
}
你也可以通过使用spring的注释@ControllerAdvice
来实现这一点。
@ControllerAdvice
public class ExceptionHandler extends ResponseEntityExceptionHandler{
/**
* Handle ServletRequestBindingException. Triggered when a 'required' request
* header parameter is missing.
*
* @param ex ServletRequestBindingException
* @param headers HttpHeaders
* @param status HttpStatus
* @param request WebRequest
* @return the ResponseEntity object
*/
@Override
protected ResponseEntity<Object> handleServletRequestBindingException(ServletRequestBindingException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
return new ResponseEntity<>(ex.getMessage(), headers, status);
}
}
在没有所需请求标头的情况下访问API时的响应是:
缺少类型为String的方法参数的请求标头“Authorization”
与此异常一样,您可以自定义所有其他异常。
如果您不想在请求映射中处理此问题,则可以创建Servlet过滤器并在Filter中查找ETag标头。如果不存在,则抛出异常。这仅适用于与过滤器的URL映射匹配的请求。
public final class MyEtagFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String etag = request.getHeader("ETag");
if(etag == null)
throw new MissingEtagHeaderException("...");
filterChain.doFilter(request, response);
}
}
您必须实现自己的MissingEtagHeaderException,或使用其他一些现有的异常。
这个比较简单。声明两个处理程序方法,一个在@RequestMapping
headers
属性中声明适当的头,另一个不在。 Spring会根据请求的内容调用适当的一个。
@RequestMapping(value = "/{blabla}", method = RequestMethod.POST, headers = "ETag")
@ResponseStatus(HttpStatus.CREATED)
public void postWith(@RequestHeader("ETag") int etag) {
// has it
}
@RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void postWithout() {
// no dice
// custom failure response
}
您也可以在不扩展ResponseEntityExceptionHandler
的情况下拦截异常:
@ControllerAdvice
public class ControllerExceptionHandler {
@ExceptionHandler(ServletRequestBindingException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<Object> handleServletRequestBindingException(ServletRequestBindingException ex) {
// return a ResponseEntity<Object> object here.
}
}