我必须在使用springboot 2.0.4.RELEASE开发的REST API中返回自定义的错误结构。
我在下面开发了控制器建议书来完成工作...除非客户端发送包含非法字符的请求。例如:http://mycompany/myapp/myservice?fields=v1[*]
([*]
应该已经过网址编码)。
客户端第一次发送此类请求时,我将此消息记录到日志中
2018-09-11 10:41:44.986信息11464-[[io-8080-exec-10] o.apache.coyote.http11.Http11Processor:解析HTTP请求时出错 标头注意:HTTP标头解析错误的进一步发生将 在调试级别记录。
java.lang.IllegalArgumentException:在 请求目标。有效字符在RFC 7230和RFC中定义 3986年 org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:479) 〜[tomcat-embed-core-8.5.32.jar:8.5.32]在 org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:684) 〜[tomcat-embed-core-8.5.32.jar:8.5.32]在 org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.32.jar:8.5.32]在 org.apache.coyote.AbstractProtocol $ ConnectionHandler.process(AbstractProtocol.java:800) [tomcat-embed-core-8.5.32.jar:8.5.32]在 org.apache.tomcat.util.net.NioEndpoint $ SocketProcessor.doRun(NioEndpoint.java:1471) [tomcat-embed-core-8.5.32.jar:8.5.32]在 org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.32.jar:8.5.32]在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_144]在 java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_144]在 org.apache.tomcat.util.threads.TaskThread $ WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.32.jar:8.5.32]在 java.lang.Thread.run(Thread.java:748)[na:1.8.0_144]
...但是没有调用我的控制器建议的任何方法,并且我收到一个http错误400(很好),带有一个空的正文(那是错误的)。接下来的时间里,除了没有记录外,其他都不会记录。
我应该怎么做才能捕获此错误并返回我的自定义错误结构?
这是(我的Controller建议的简化代码):
package com.renault.api.examples.springboot;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
@ControllerAdvice
public class ExceptionHandler extends ResponseEntityExceptionHandler {
public static final class CustomError {
// custom attributes removed for publication
}
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionHandler.class);
private static final String UNEXPECTED_EXCEPTION_MESSAGE = "An unexpected exception occurred";
@Override
protected ResponseEntity<Object> handleTypeMismatch(TypeMismatchException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleTypeMismatch");
return new ResponseEntity<Object>(new CustomError(), headers, status);
}
@Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleHttpRequestMethodNotSupported");
return super.handleHttpRequestMethodNotSupported(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleHttpMediaTypeNotSupported");
return super.handleHttpMediaTypeNotSupported(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleHttpMediaTypeNotAcceptable");
return super.handleHttpMediaTypeNotAcceptable(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleMissingPathVariable(MissingPathVariableException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
System.out.println("handleMissingPathVariable");
return super.handleMissingPathVariable(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleMissingServletRequestParameter");
return super.handleMissingServletRequestParameter(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleServletRequestBindingException(ServletRequestBindingException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleServletRequestBindingException");
return super.handleServletRequestBindingException(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleConversionNotSupported(ConversionNotSupportedException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleConversionNotSupported");
return super.handleConversionNotSupported(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleHttpMessageNotReadable");
return super.handleHttpMessageNotReadable(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleHttpMessageNotWritable(HttpMessageNotWritableException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleHttpMessageNotWritable");
return super.handleHttpMessageNotWritable(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleMethodArgumentNotValid");
return super.handleMethodArgumentNotValid(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleMissingServletRequestPart(MissingServletRequestPartException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println("handleMissingServletRequestPart");
return super.handleMissingServletRequestPart(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status,
WebRequest request) {
System.out.println("handleBindException");
return super.handleBindException(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
System.out.println("handleNoHandlerFoundException");
return super.handleNoHandlerFoundException(ex, headers, status, request);
}
@Override
protected ResponseEntity<Object> handleAsyncRequestTimeoutException(AsyncRequestTimeoutException ex,
HttpHeaders headers, HttpStatus status, WebRequest webRequest) {
System.out.println("handleAsyncRequestTimeoutException");
return super.handleAsyncRequestTimeoutException(ex, headers, status, webRequest);
}
@Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers,
HttpStatus status, WebRequest request) {
System.out.println("handleExceptionInternal");
return super.handleExceptionInternal(ex, body, headers, status, request);
}
/** Handles all exceptions not processed by spring boot thrown during request processing.
* <br>this means the errors like "path not found", "wrong argument" are not processed by this method.
* @param ex The exception that occurs.
* @param request The request that sends the exception.
* @return The response to send to client. For publication, all exceptions are considered unexpected => http error 500
*/
@org.springframework.web.bind.annotation.ExceptionHandler(value= {Exception.class})
protected ResponseEntity<Object> handle(Exception ex, WebRequest request) {
LOGGER.error(UNEXPECTED_EXCEPTION_MESSAGE, ex);
CustomError response = new CustomError();
// Fill custom error attributes ... removed for publication
return handleExceptionInternal(ex, response, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
}
/** Handles "standard" errors, like "path not found".
* @return an ErrorAttributes object describing the attributes of the response's body.
*/
@Bean
public ErrorAttributes errorAttributes() {
return new DefaultErrorAttributes() {
@Override
public int getOrder() {
System.out.println("getOrder is called");
return super.getOrder();
}
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
System.out.println("resolveException is called");
return super.resolveException(request, response, handler, ex);
}
@Override
public Throwable getError(WebRequest webRequest) {
System.out.println("getError is called");
return super.getError(webRequest);
}
@Override
public Map<String, Object> getErrorAttributes(WebRequest request, boolean includeStackTrace) {
System.out.println("getErrorAttributes is called");
CustomError err = new CustomError();
// Reuse default attributes to fill custom error ... removed for publication
@SuppressWarnings("unchecked")
Map<String, Object> map = OBJECT_MAPPER.convertValue(err, Map.class);
return map;
}
};
}
}
谢谢