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

前端 未结 4 800
醉梦人生
醉梦人生 2021-01-30 23:56

I am developing a REST service using SpringMVC, where I have @RequestMapping at class and method level.

This application is currently configured to return error-page js

相关标签:
4条回答
  • 2021-01-31 00:34

    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). You can find documentation here. Take a look at section 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.

    0 讨论(0)
  • 2021-01-31 00:40

    After digging around DispatcherServlet and HttpServletBean.init() in SpringFramework I see that its possible in 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 is false by default and we should enable that in 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.

    @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 :)

    {"message":"URL does not exist","url":"http://localhost:8080/service/patientssd"}
    
    0 讨论(0)
  • 2021-01-31 00:50

    If you are using Spring Boot, set BOTH of these two properties:

    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
    @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".

    To disable the unknown url mapping to /**, you need

    spring.resources.add-mappings=false ,
    

    which is why the two properties together produce the desired behavior.

    0 讨论(0)
  • 2021-01-31 00:51

    you can return json in the location below,that /handle/404.

    <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. for example.

    @RestController
    @RequestMapping(value = "handle")
    public class HttpErrorController {
       @RequestMapping(value = "404")
       public String handle404() {
          return "404 error";
       }
    }
    
    0 讨论(0)
提交回复
热议问题