Spring MVC can't handle 404 from Resource Handler?

我们两清 提交于 2020-01-13 10:37:31

问题


I'm using Spring MVC 4.3.11.RELEASE and have a vanilla resource handler for static resources. It's working fine - for resources that exist. However if not, it appears to return a 404 to the DispatcherServlet which is happy with that response since it found a handler. I've got ControllerAdvice for NoHandlerFoundException which works fine for controllers but isn't meant to handle this case. So Spring MVC punts completely and I get the nasty Tomcat 404 response. I can find no way to configure handling for this case so I can return a proper response.

With TRACE enabled for Spring, you see the following for such a request:

2018-03-15T14:22:05,361 TRACE [] DispatcherServlet          - Bound request context to thread: org.apache.catalina.connector.RequestFacade@597aa896
2018-03-15T14:22:05,361 DEBUG [] DispatcherServlet          - DispatcherServlet with name 'dispatcher' processing GET request for [/creditcard/static/doh]
2018-03-15T14:22:05,361 TRACE [] DispatcherServlet          - Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@4b720a14] in DispatcherServlet with name 'dispatcher'
2018-03-15T14:22:05,361 DEBUG [] questMappingHandlerMapping - Looking up handler method for path /static/doh
2018-03-15T14:22:05,364 DEBUG [] questMappingHandlerMapping - Did not find handler method for [/static/doh]
2018-03-15T14:22:05,364 TRACE [] DispatcherServlet          - Testing handler map [org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@67db7dde] in DispatcherServlet with name 'dispatcher'
2018-03-15T14:22:05,364 TRACE [] BeanNameUrlHandlerMapping  - No handler mapping found for [/static/doh]
2018-03-15T14:22:05,364 TRACE [] DispatcherServlet          - Testing handler map [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@4698270f] in DispatcherServlet with name 'dispatcher'
2018-03-15T14:22:05,364 DEBUG [] SimpleUrlHandlerMapping    - Matching patterns for request [/static/doh] are [/static//**]
2018-03-15T14:22:05,364 DEBUG [] SimpleUrlHandlerMapping    - URI Template variables for request [/static/doh] are {}
2018-03-15T14:22:05,364 DEBUG [] SimpleUrlHandlerMapping    - Mapping [/static/doh] to HandlerExecutionChain with handler [ResourceHttpRequestHandler [locations=[ServletContext resource [/static//]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@20537c7e]]] and 1 interceptor
2018-03-15T14:22:05,364 TRACE [] DispatcherServlet          - Testing handler adapter [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@442b38d3]
2018-03-15T14:22:05,364 TRACE [] DispatcherServlet          - Testing handler adapter [org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter@3128c8a7]
2018-03-15T14:22:05,364 DEBUG [] DispatcherServlet          - Last-Modified value for [/creditcard/static/doh] is: -1
2018-03-15T14:22:05,364 TRACE [] ResourceHttpRequestHandler - Applying "invalid path" checks to path: doh
2018-03-15T14:22:05,364 TRACE [] PathResourceResolver       - Resolving resource for request path "doh"
2018-03-15T14:22:05,364 TRACE [] PathResourceResolver       - Checking location: ServletContext resource [/static//]
2018-03-15T14:22:05,364 TRACE [] PathResourceResolver       - No match for location: ServletContext resource [/static//]
2018-03-15T14:22:05,364 TRACE [] ResourceHttpRequestHandler - No matching resource found - returning 404
2018-03-15T14:22:05,364 DEBUG [] DispatcherServlet          - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling
2018-03-15T14:22:05,364 TRACE [] DispatcherServlet          - Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@597aa896
2018-03-15T14:22:05,364 DEBUG [] DispatcherServlet          - Successfully completed request

Thoughts?


回答1:


I had the same issue. My solution as follows:

  • spring.resources.add-mappings=false (either in yaml or application.properties)
  • in Config of WebMvcConfigurer 'addResourceHandlers' method add all your mappings, e.g.:

    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/home.html**")
                    .addResourceLocations("classpath:/static/views/home/");
        }
    
        @Override
        public void configureDefaultServletHandling(
                  DefaultServletHandlerConfigurer configurer) {
            // DO not enable this ! 
            // configurer.enable();
            // Remove this method! 
        }
    }
    
  • must remove default servlet handler, as it will try to handle and return with status 404, but never throws the NoHandlerFoundException

  • add GlobalExceptionHandler Controller advice:

    @ControllerAdvice
    public class GlobalExceptionHandler {
        @ExceptionHandler(NoHandlerFoundException.class)
        public String handleNotFoundError(Exception ex) {
            return "redirect:/your404page";
        }
    }
    

Hope this helps! For me it works perfectly!




回答2:


The mrkurtan answer only works for spring-boot, as spring.resources.add-mappings=false is a spring-boot configuration

so re-writing required configuration to through NoHandlerFoundException and handle it.

  1. Create a class GlobalExceptionHandler annotated with @ControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler 
{
    @ExceptionHandler(NoHandlerFoundException.class)
    public String handleNotFoundError(Exception ex) 
    {
        return "redirect:/yourCustom404page";
    }
}
  1. By default, when a page/resource does not exist the servlet container will throw a default 404 page. If you want a custom 404 response then you need to tell DispatcherServlet to throw the exception if no handler is found. We can do this by setting the throwExceptionIfNoHandlerFound servlet initialization parameter to true

In spring-mvc java based configuration is

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
    ...

    @Override
    protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) 
    {
        final DispatcherServlet servlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
        servlet.setThrowExceptionIfNoHandlerFound(true);
        return servlet;
    }

}

if xml based configuration, initialize your dispatcher servlet like this

<servlet>
    <servlet-name>dispatcher</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>
</servlet>


来源:https://stackoverflow.com/questions/49302130/spring-mvc-cant-handle-404-from-resource-handler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!