简体   繁体   English

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

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

I am developing a REST service using SpringMVC, where I have @RequestMapping at class and method level. 我正在使用SpringMVC开发REST服务,其中在类和方法级别使用@RequestMapping。

This application is currently configured to return error-page jsp configured in web.xml. 当前已将该应用程序配置为返回在web.xml中配置的错误页面jsp。

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

I however want to return custom JSON instead of this error page. 但是,我想返回自定义JSON而不是此错误页面。

I am able to handle exception and return json for other exceptions, by writing this in controller, but not sure how and where to write the logic to return JSON when the url does not exist at all. 通过在控制器中编写此代码,我能够处理异常并为其他异常返回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);

        }

I tried @ControllerAdvice, it works for other exception scenarios, but not when mapping is not avaialble, 我尝试了@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);
    }


}

After digging around DispatcherServlet and HttpServletBean.init() in SpringFramework I see that its possible in Spring 4. 在SpringFramework中研究了DispatcherServlet和HttpServletBean.init()之后,我发现在Spring 4中它是可能的。

org.springframework.web.servlet.DispatcherServlet 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 is false by default and we should enable that in web.xml 默认情况下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>

And then you can catch it in a class annotated with @ControllerAdvice using this method. 然后,您可以使用此方法将其捕获在带有@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);
}

Which allows me to return JSON response for bad URLs for which no mapping exist, instead of redirecting to a JSP page :) 这使我可以为不存在映射的错误URL返回JSON响应,而不是重定向到JSP页面:)

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

If you are using Spring Boot, set BOTH of these two properties: 如果您使用的是Spring Boot,请同时设置以下两个属性:

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

Now your @ControllerAdvice annotated class can handle the "NoHandlerFoundException", as below. 现在,您的@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);
    }

}

note it is not sufficient to only specify this property: 请注意,仅指定此属性是不够的:

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

, as by default Spring maps unknown urls to /**, so there really never is "no handler found". ,因为默认情况下,Spring会将未知的URL映射到/ **,所以实际上永远不会“找不到处理程序”。

To disable the unknown url mapping to /**, you need 要禁用到/ **的未知URL映射,您需要

spring.resources.add-mappings=false ,

which is why the two properties together produce the desired behavior. 这就是两个属性共同产生所需行为的原因。

If you're using spring 3.2 or later you can use a controller advice ( @ControllerAdvice ) to deal with, amongst other things, mapping errors (404's). 如果您使用的是Spring 3.2或更高版本,则可以使用控制器建议( @ControllerAdvice )处理映射错误(404)。 You can find documentation here . 您可以在此处找到文档 Take a look at section 17.11. 看一下第17.11节。 You can use this, for example, to provide more detailed logging on why your request bindings aren't being matched for specific urls, or to simply return a more specific response than a generic 404. 例如,您可以使用它来提供更详细的日志记录,以了解为什么您的请求绑定与特定的URL不匹配,或者仅返回比通用404更特定的响应。

you can return json in the location below,that /handle/404 . 您可以在/ handle / 404下面的位置返回json。

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

after you config this in web.xml,a 404 error will redirect to /handle/404 ,and you can create a controller with this mapping and return a json result. 在web.xml中配置此命令后,将出现404错误,该错误将重定向到/ handle / 404 ,您可以使用此映射创建一个控制器并返回json结果。 for example. 例如。

@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