Java Spring boot 404错误自定义错误响应ReST
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30917782/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring boot 404 error custom error response ReST
提问by Markus
I'm using Spring boot for hosting a REST API. Instead of having the standard error response I would like to always send a JSON response even if a browser is accessing the URL and as well a custom data structure.
我正在使用 Spring Boot 来托管 REST API。即使浏览器正在访问 URL 以及自定义数据结构,我也希望始终发送 JSON 响应,而不是标准错误响应。
I can do this with @ControllerAdvice and @ExceptionHandler for custom exceptions. But I can't find any good ways of doing this for standard and handled errors like 404 and 401.
对于自定义异常,我可以使用 @ControllerAdvice 和 @ExceptionHandler 来做到这一点。但是对于像 404 和 401 这样的标准和已处理错误,我找不到任何好的方法来执行此操作。
Are there any good patterns of how to do this?
有没有什么好的模式可以做到这一点?
回答by Opal
It seems that you need to introduce an appropriately annotated method, e.g. for unsupported media type (415) it will be:
似乎您需要引入一个适当注释的方法,例如对于不受支持的媒体类型(415),它将是:
@ExceptionHandler(MethodArgumentNotValidException)
public ResponseEntity handleMethodArgumentNotValidException(HttpServletRequest req, MethodArgumentNotValidException e) {
logger.error('Caught exception', e)
def response = new ExceptionResponse(
error: 'Validation error',
exception: e.class.name,
message: e.bindingResult.fieldErrors.collect { "'$it.field' $it.defaultMessage" }.join(', '),
path: req.servletPath,
status: BAD_REQUEST.value(),
timestamp: currentTimeMillis()
)
new ResponseEntity<>(response, BAD_REQUEST)
}
However it may not be possible since 401 and 404 may be thrown before they reach DispatcherServlet
- in this case ControllerAdvice
will not work.
然而,这可能是不可能的,因为 401 和 404 可能会在它们到达之前被抛出DispatcherServlet
- 在这种情况下ControllerAdvice
将不起作用。
回答by hyness
You can add custom ErrorPageobjects which correlate to the error-page definition in web.xml. Spring Boot provides an example...
您可以添加与 web.xml 中的错误页面定义相关的自定义ErrorPage对象。 Spring Boot 提供了一个示例...
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
return new MyCustomizer();
}
// ...
private static class MyCustomizer implements EmbeddedServletContainerCustomizer {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.addErrorPages(new ErrorPage(HttpStatus.UNAUTHORIZED, "/unauthorized.html"));
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/not-found.html"));
}
}
EDIT:While I think the method above will work if you make the error pages rest controllers, an even easier way would be to include a custom ErrorControllerlike the one below...
编辑:虽然我认为如果您使错误页面休息控制器,上面的方法将起作用,但更简单的方法是包含一个自定义的ErrorController如下所示......
@Bean
public ErrorController errorController(ErrorAttributes errorAttributes) {
return new CustomErrorController(errorAttributes);
}
// ...
public class CustomErrorController extends BasicErrorController {
public CustomErrorController(ErrorAttributes errorAttributes) {
super(errorAttributes);
}
@Override
@RequestMapping(value = "${error.path:/error}")
@ResponseBody
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
ResponseEntity<Map<String, Object>> error = super.error(request);
HttpStatus statusCode = error.getStatusCode();
switch (statusCode) {
case NOT_FOUND:
return getMyCustomNotFoundResponseEntity(request);
case UNAUTHORIZED:
return getMyCustomUnauthorizedResponseEntity(request);
default:
return error;
}
}
}
回答by maxie
404 error is handled by DispatcherServlet. there is a property throwExceptionIfNoHandlerFound, which you can override.
404 错误由 DispatcherServlet 处理。有一个属性 throwExceptionIfNoHandlerFound,您可以覆盖它。
In Application class you can create a new bean:
在 Application 类中,您可以创建一个新 bean:
@Bean
DispatcherServlet dispatcherServlet () {
DispatcherServlet ds = new DispatcherServlet();
ds.setThrowExceptionIfNoHandlerFound(true);
return ds;
}
...and then catch the NoHandlerFoundException exception in
...然后在中捕获 NoHandlerFoundException 异常
@EnableWebMvc
@ControllerAdvice
public class GlobalControllerExceptionHandler {
@ExceptionHandler
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ErrorMessageResponse requestHandlingNoHandlerFound(final NoHandlerFoundException ex) {
doSomething(LOG.debug("text to log"));
}
}
回答by Ilya Ovesnov
I've provided the sample solution on how to override response for 404 case. The solution is pretty much simple and I am posting sample code but you can find more details on the original thread: Spring Boot Rest - How to configure 404 - resource not found
我已经提供了有关如何覆盖 404 案例的响应的示例解决方案。解决方案非常简单,我发布了示例代码,但您可以在原始线程中找到更多详细信息:Spring Boot Rest - How to configure 404 - resource not found
First: define Controller that will process error cases and override response:
首先:定义将处理错误情况并覆盖响应的控制器:
@ControllerAdvice
public class ExceptionHandlerController {
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(value= HttpStatus.NOT_FOUND)
@ResponseBody
public ErrorResponse requestHandlingNoHandlerFound() {
return new ErrorResponse("custom_404", "message for 404 error code");
}
}
Second: you need to tell Spring to throw exception in case of 404 (could not resolve handler):
第二:您需要告诉 Spring 在 404 的情况下抛出异常(无法解析处理程序):
@SpringBootApplication
@EnableWebMvc
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
DispatcherServlet dispatcherServlet = (DispatcherServlet)ctx.getBean("dispatcherServlet");
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
}
}
回答by ogradyjd
Please see Spring Boot REST service exception handling. It shows how to tell the dispatcherservlet to emit exceptions for "no route found" and then how to catch those exceptions. We (the place I work) are using this in production for our REST services right now.
请参阅Spring Boot REST 服务异常处理。它展示了如何告诉 dispatcherservlet 为“未找到路由”发出异常,然后如何捕获这些异常。我们(我工作的地方)现在正在为我们的 REST 服务在生产中使用它。
回答by Emdadul Sawon
Summing up all answers and comment, I think the best way to do this is-
总结所有答案和评论,我认为最好的方法是-
First, tell spring boot to throw exception in case of no handler found in application.properties
首先,告诉 spring boot 在没有找到处理程序的情况下抛出异常 application.properties
spring.mvc.throw-exception-if-no-handler-found=true
Then handle NoHandlerFoundException
in your application. I handle this by following way
然后处理NoHandlerFoundException
您的应用程序。我通过以下方式处理这个
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NoHandlerFoundException.class)
public void handleNotFoundError(HttpServletResponse response, NoHandlerFoundException ex) {
ErrorDto errorDto = Errors.URL_NOT_FOUND.getErrorDto();
logger.error("URL not found exception: " + ex.getRequestURL());
prepareErrorResponse(response, HttpStatus.NOT_FOUND, errorDto);
}
}
回答by Adewagold
I was having the same issue but fixed it using a different method. To return 404, 401and other status in a custom response, you can now add the response status to the custom exception class and call it from your exception handler.
我遇到了同样的问题,但使用不同的方法修复了它。要在自定义响应中返回404、401和其他状态,您现在可以将响应状态添加到自定义异常类并从您的异常处理程序中调用它。
With spring utility class AnnotationUtils, you can get the status of any of the defined custom exceptions with the findAnnotation method and it will return the appropriate status using whatever annotation you defined for the exceptions including not found.
使用 spring 实用程序类AnnotationUtils,您可以使用 findAnnotation 方法获取任何定义的自定义异常的状态,并且它将使用您为异常定义的任何注释(包括未找到)返回适当的状态。
Here's my @RestControllerAdvice
这是我的@RestControllerAdvice
@RestControllerAdvice
public class MainExceptionHandler extends Throwable{
@ExceptionHandler(BaseException.class)
ResponseEntity<ExceptionErrorResponse> exceptionHandler(GeneralMainException e)
{
ResponseStatus status = AnnotationUtils.findAnnotation(e.getClass(),ResponseStatus.class);
if(status != null)
{
return new ResponseEntity<>(new ExceptionErrorResponse(e.getCode(),e.getMessage()),status.code());
}
}
CustomParamsException to return Bad request status
CustomParamsException 返回错误的请求状态
@ResponseStatus(value= HttpStatus.BAD_REQUEST)
public class CustomParamsException extends BaseException {
private static final String CODE = "400";
public CustomParamsException(String message) {
super(CODE, message);
}
}
Details not found to return Not Found Status
未找到详细信息以返回未找到状态
@ResponseStatus(value= HttpStatus.NOT_FOUND)
public class DetailsNotException extends BaseException {
private static final String CODE = "400";
public DetailsNotException(String message) {
super(CODE, message);
}
}
A GeneralMainException to extend Excetion
用于扩展 Excetion 的 GeneralMainException
public class GeneralMainException extends Exception {
private String code;
private String message;
public GeneralMainException (String message) {
super(message);
}
public GeneralMainException (String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
You can decide to handle other system exceptions by including it to the controller advice.
您可以通过将其包含在控制器建议中来决定处理其他系统异常。
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
ExceptionErrorResponse sysError(Exception e)
{
return new ExceptionErrorResponse(""1002", e.getMessage());
}
回答by fightlight
For those Spring Boot 2 users who don't wanna use @EnableWebMvc
对于那些不想使用的 Spring Boot 2 用户 @EnableWebMvc
application.properties
应用程序属性
server.error.whitelabel.enabled=false
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
ControllerAdvice
控制器建议
@RestControllerAdvice
public class ExceptionResolver {
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public HashMap<String, String> handleNoHandlerFound(NoHandlerFoundException e, WebRequest request) {
HashMap<String, String> response = new HashMap<>();
response.put("status", "fail");
response.put("message", e.getLocalizedMessage());
return response;
}
}
回答by R J
Starting with Spring version 5 can use class ResponseStatusException:
从 Spring 版本 5 开始可以使用类 ResponseStatusException:
@GetMapping("example")
public ResponseEntity example() {
try {
throw new MyException();
} catch (MyException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "My Exception", e);
}
}