为什么在Spring中有两种方法来处理静态资源(addResourceHandlers和容器的Default Servlet“)?

我是Spring的新手。 我注意到在处理静态资源时,有两种选择:


选项1:

如果 Spring的DispatcherServlet映射到/使用下面的代码,这使得它成为“默认Servlet”,则可以使用RequestMapping批注将某些静态资源映射到Spring处理程序(覆盖AbstractAnnotationConfigDispatcherServletInitializer类):

 @Override protected String[] getServletMappings() { return new String[]{"/"}; } 

然后我们仍然可以启用容器的“Default Servlet”来处理那些静态资源,其URL模式不被Spring请求映射覆盖(覆盖WebMvcConfigurerAdapter类):

 @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } 

这基本上使用servlet容器的“Default Servlet”作为catch-all来处理Spring的DispatcherServlet 错过的所有静态资源。


选项2:

(重写WebMvcConfigurerAdapter类)

 @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { super.addResourceHandlers(registry); registry.addResourceHandler("*.efi").addResourceLocations("/"); } 

  • 为什么有两种选择?
  • 这些方法之间的主要区别是什么?
  • 还有其他选择吗?

我通常选择2,因为我想坚持Spring,但我知道这不是一个强有力的理由。


一些与静态资源处理相关的参考:

  • 用Spring服务静态资源
  • Spring Framework 4.1 – 处理静态Web资源
  • Spring MVC – 如何在JSP页面中包含JS或CSS文件

添加1

似乎选项2在资源映射方面提供了更大的灵活性。 甚至可以映射WEB-INF文件夹中的资源。

下面是一个具体的例子,说明退回“默认”Servlet服务资源不适用。

这是上述方法的典型实现:

 @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); return; } 

但是,目前在Spring 4 处理404错误的最佳实践似乎是使用setThrowExceptionIfNoHandlerFound

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

不幸的是,根据DispatcherServlet的文档:

请注意,如果使用DefaultServletHttpRequestHandler ,则请求将始终转发到默认servlet,并且在这种情况下永远不会抛出NoHandlerFoundException

的确,情况确实如此。 结合上述两种方法不会导致触发NoHandlerFoundException ,这反过来又会阻止我的404自定义错误页面解析。 现在,如果我要注释掉我的configureDefaultServletHandling方法,则抛出NoHandlerFoundException并且我的error handling(通过链接答案中显示的@ControllerAdvice )解析为我的自定义’notFoundPage’。

不幸的是,现在这意味着我的静态资源(即’default.css’)没有得到解决:

 DEBUG org.springframework.web.servlet.DispatcherServlet - Handler execution resulted in exception - forwarding to resolved error view: ModelAndView: reference to view with name 'notFoundPage'; model is {} org.springframework.web.servlet.NoHandlerFoundException: No handler found for GET /webapp-test/style/default.css 

我认为没有办法调和这两种方法,这样它们就不会相互干扰。 我的结论是,在这种情况下,“默认Servlet”方法不适合提供静态资源,这使我们得到了addResourceHandlers方法。

使用addResourceHandlers方法的好处包括:

  • …从Web应用程序根目录以外的位置提供静态资源, 包括类路径上的位置
  • 缓存周期属性可用于设置远期未来到期标头,以便客户端更有效地使用它们。
  • 处理程序还正确地评估Last-Modified标头(如果存在),以便适当地返回304状态代码,从而避免客户端已缓存的资源的不必要开销。

另请参阅此答案以获取更复杂的示例,说明如何使用默认servlet处理静态资源会导致不必要的副作用。