问题
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.
- Create a class
GlobalExceptionHandlerannotated with@ControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler
{
@ExceptionHandler(NoHandlerFoundException.class)
public String handleNotFoundError(Exception ex)
{
return "redirect:/yourCustom404page";
}
}
- 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
DispatcherServletto throw the exception if no handler is found. We can do this by setting thethrowExceptionIfNoHandlerFoundservlet initialization parameter totrue
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