繁体   English   中英

Spring MVC REST通过返回JSON处理错误的网址(404)

[英]Spring MVC REST Handing Bad Url (404) by returning JSON

我正在使用SpringMVC开发REST服务,其中在类和方法级别使用@RequestMapping。

当前已将该应用程序配置为返回在web.xml中配置的错误页面jsp。

<error-page>
    <error-code>404</error-code>
    <location>/resourceNotFound</location>
</error-page>

但是,我想返回自定义JSON而不是此错误页面。

通过在控制器中编写此代码,我能够处理异常并为其他异常返回json,但不确定在URL根本不存在时如何以及在何处编写返回JSON的逻辑。

    @ExceptionHandler(TypeMismatchException.class)
        @ResponseStatus(value=HttpStatus.NOT_FOUND)
        @ResponseBody
        public ResponseEntity<String> handleTypeMismatchException(HttpServletRequest req, TypeMismatchException ex) {

            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Type", "application/json; charset=utf-8");
            Locale locale = LocaleContextHolder.getLocale();
            String errorMessage = messageSource.getMessage("error.patient.bad.request", null, locale);

            errorMessage += ex.getValue();
            String errorURL = req.getRequestURL().toString();

            ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
            return new ResponseEntity<String>(errorInfo.toJson(), headers, HttpStatus.BAD_REQUEST);

        }

我尝试了@ControllerAdvice,它适用于其他异常情况,但是当映射不可用时不起作用,

@ControllerAdvice
public class RestExceptionProcessor {

    @Autowired
    private MessageSource messageSource;

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(value=HttpStatus.NOT_FOUND)
    @ResponseBody
    public ResponseEntity<String> requestMethodNotSupported(HttpServletRequest req, HttpRequestMethodNotSupportedException ex) {
        Locale locale = LocaleContextHolder.getLocale();
        String errorMessage = messageSource.getMessage("error.patient.bad.id", null, locale);

        String errorURL = req.getRequestURL().toString();

        ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
        return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(NoSuchRequestHandlingMethodException.class)
    @ResponseStatus(value=HttpStatus.NOT_FOUND)
    @ResponseBody
    public ResponseEntity<String> requestHandlingMethodNotSupported(HttpServletRequest req, NoSuchRequestHandlingMethodException ex) {
        Locale locale = LocaleContextHolder.getLocale();
        String errorMessage = messageSource.getMessage("error.patient.bad.id", null, locale);

        String errorURL = req.getRequestURL().toString();

        ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
        return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
    }


}

在SpringFramework中研究了DispatcherServlet和HttpServletBean.init()之后,我发现在Spring 4中它是可能的。

org.springframework.web.servlet.DispatcherServlet

/** Throw a NoHandlerFoundException if no Handler was found to process this request? **/
private boolean throwExceptionIfNoHandlerFound = false;

protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
    if (pageNotFoundLogger.isWarnEnabled()) {
        String requestUri = urlPathHelper.getRequestUri(request);
        pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + requestUri +
                "] in DispatcherServlet with name '" + getServletName() + "'");
    }
    if(throwExceptionIfNoHandlerFound) {
        ServletServerHttpRequest req = new ServletServerHttpRequest(request);
        throw new NoHandlerFoundException(req.getMethod().name(),
                req.getServletRequest().getRequestURI(),req.getHeaders());
    } else {
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
    }
}

默认情况下throwExceptionIfNoHandlerFound为false,我们应该在web.xml中启用它

<servlet>
    <servlet-name>appServlet</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>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>

然后,您可以使用此方法将其捕获在带有@ControllerAdvice注释的类中。

@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> requestHandlingNoHandlerFound(HttpServletRequest req, NoHandlerFoundException ex) {
    Locale locale = LocaleContextHolder.getLocale();
    String errorMessage = messageSource.getMessage("error.bad.url", null, locale);

    String errorURL = req.getRequestURL().toString();

    ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
    return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}

这使我可以为不存在映射的错误URL返回JSON响应,而不是重定向到JSP页面:)

{"message":"URL does not exist","url":"http://localhost:8080/service/patientssd"}

如果您使用的是Spring Boot,请同时设置以下两个属性:

spring.resources.add-mappings=false
spring.mvc.throw-exception-if-no-handler-found=true

现在,您的@ControllerAdvice带注释的类可以处理“ NoHandlerFoundException”,如下所示。

@ControllerAdvice
@RequestMapping(produces = "application/json")
@ResponseBody
public class RestControllerAdvice {

    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity<Map<String, Object>> unhandledPath(final NoHandlerFoundException e) {
        Map<String, Object> errorInfo = new LinkedHashMap<>();
        errorInfo.put("timestamp", new Date());
        errorInfo.put("httpCode", HttpStatus.NOT_FOUND.value());
        errorInfo.put("httpStatus", HttpStatus.NOT_FOUND.getReasonPhrase());
        errorInfo.put("errorMessage", e.getMessage());
        return new ResponseEntity<Map<String, Object>>(errorInfo, HttpStatus.NOT_FOUND);
    }

}

请注意,仅指定此属性是不够的:

spring.mvc.throw-exception-if-no-handler-found=true

,因为默认情况下,Spring会将未知的URL映射到/ **,所以实际上永远不会“找不到处理程序”。

要禁用到/ **的未知URL映射,您需要

spring.resources.add-mappings=false ,

这就是两个属性共同产生所需行为的原因。

如果您使用的是Spring 3.2或更高版本,则可以使用控制器建议( @ControllerAdvice )处理映射错误(404)。 您可以在此处找到文档 看一下第17.11节。 例如,您可以使用它来提供更详细的日志记录,以了解为什么您的请求绑定与特定的URL不匹配,或者仅返回比通用404更特定的响应。

您可以在/ handle / 404下面的位置返回json。

<error-page>
    <error-code>404</error-code>
    <location>/handle/404</location>
</error-page>

在web.xml中配置此命令后,将出现404错误,该错误将重定向到/ handle / 404 ,您可以使用此映射创建一个控制器并返回json结果。 例如。

@RestController
@RequestMapping(value = "handle")
public class HttpErrorController {
   @RequestMapping(value = "404")
   public String handle404() {
      return "404 error";
   }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM