为什么在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处理静态资源会导致不必要的副作用。