【问题标题】:Spring MVC can't handle 404 from Resource Handler?Spring MVC 无法处理来自 Resource Handler 的 404?
【发布时间】:2018-03-15 14:30:47
【问题描述】:

我正在使用 Spring MVC 4.3.11.RELEASE 并有一个用于静态资源的 vanilla 资源处理程序。它工作正常 - 对于存在的资源。但是,如果不是,它似乎会向 DispatcherServlet 返回一个 404,因为它找到了一个处理程序,所以它对该响应感到满意。我有用于 NoHandlerFoundException 的 ControllerAdvice,它适用于控制器,但并不意味着处理这种情况。所以 Spring MVC 完全退出,我得到了讨厌的 Tomcat 404 响应。我无法为这种情况配置处理,因此我可以返回正确的响应。

为 Spring 启用 TRACE 后,您会看到以下请求:

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

想法?

【问题讨论】:

  • 你解决了吗?我目前遇到了同样的问题......
  • 解决这个问题的一个简单方法是禁用默认资源处理,这会在你的 application.properties 中添加 /webjars/** 和 /** 的映射:spring.resources.add-mappings=false 但显然你不能总是这样做(在我的情况下,我需要 Swagger)

标签: java spring spring-mvc


【解决方案1】:

我有同样的问题。我的解决方案如下:

  • spring.resources.add-mappings=false(在 yaml 或 application.properties 中)
  • 在 WebMvcConfigurer 'addResourceHandlers' 方法的 Config 中添加所有映射,例如:

    @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! 
        }
    }
    
  • 必须删除默认的 servlet 处理程序,因为它会尝试处理并返回状态 404,但不会抛出 NoHandlerFoundException

  • 添加 GlobalExceptionHandler 控制器建议:

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

希望这会有所帮助!对我来说,它完美无缺!

【讨论】:

  • 你救了我!谢谢
【解决方案2】:

mrkurtan 答案仅适用于 spring-boot,因为 spring.resources.add-mappings=false 是 spring-boot 配置

所以重写所需的配置以通过 NoHandlerFoundException 并处理它。

  1. 创建一个带有@ControllerAdvice注解的类GlobalExceptionHandler
@ControllerAdvice
public class GlobalExceptionHandler 
{
    @ExceptionHandler(NoHandlerFoundException.class)
    public String handleNotFoundError(Exception ex) 
    {
        return "redirect:/yourCustom404page";
    }
}
  1. 默认情况下,当页面/资源不存在时,servlet 容器将抛出默认的 404 页面。如果您想要自定义 404 响应,则需要告诉 DispatcherServlet 在未找到处理程序时抛出异常。我们可以通过将throwExceptionIfNoHandlerFound servlet 初始化参数设置为true 来做到这一点

在spring-mvc中基于java的配置是

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
    ...

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

}

如果是基于 xml 的配置,像这样初始化你的调度器 servlet

<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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-13
    • 2016-06-05
    • 1970-01-01
    • 1970-01-01
    • 2016-11-03
    • 2016-01-24
    • 1970-01-01
    • 2014-01-01
    相关资源
    最近更新 更多