java - 为什么在 Spring 中有 2 种处理静态资源的方式(addResourceHandlers 和容器的 Default Servlet")?

标签 java spring spring-mvc configuration

我是 Spring 的新手。我注意到在处理静态资源时,有两个选项可用:


选项 1:

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

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

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

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

这基本上使用 servlet 容器的“默认 Servlet”作为catch-all 来处理所有遗漏的静态资源/strong> 由 Spring 的 DispatcherServlet 实现。


选项 2:

(重写 WebMvcConfigurerAdapter 类)

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

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

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


一些与静态资源处理相关的引用:


添加 1

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

最佳答案

这是一个具体的例子,当Falling Back On the "Default" Servlet To Serve Resources不适用。

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

@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 的文档:

Note that if DefaultServletHttpRequestHandler is used, then requests will always be forwarded to the default servlet and a NoHandlerFoundException would never be thrown in that case.

的确如此。结合上述两种方法不会导致触发 NoHandlerFoundException,这反过来会阻止我的 404 自定义错误页面解析。现在,如果我要注释掉我的 configureDefaultServletHandling 方法,则会抛出 NoHandlerFoundException 并且我的错误处理(通过 @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 method 的好处之一是:

  • ...从 Web 应用程序根目录以外的位置提供静态资源,包括类路径中的位置
  • cache-period 属性可用于设置远期到期 header ,以便客户端更有效地利用它们。
  • 处理程序还会正确评估 Last-Modified header (如果存在),以便适本地返回 304 状态代码,避免对已由客户端缓存的资源产生不必要的开销。

另见 this answer有关使用默认 servlet 处理静态资源如何导致不需要的副作用的更复杂示例。

关于java - 为什么在 Spring 中有 2 种处理静态资源的方式(addResourceHandlers 和容器的 Default Servlet")?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34279705/

相关文章:

java - 使用 PowerMock 添加测试后 Spring Web 应用程序无法启动

java - MockMVC jUnit Spring 测试

java - Spring Boot Multi-Module maven项目重新打包失败

java - 将 CMS 与 Spring MVC 应用程序集成

java - 新手尝试使用Java ArrayList来存储从数据库获取的ResultSet

java - Hibernate 4 connection.autocommit=false 忽略

java - 在 java 上实现的工作 oauth2 提供程序服务器

java - Spring Boot 和 Ajax 响应

java - 使用 spring boot 将 JSON 反序列化为具有通用对象列表的 POJO

java - Spring Rest Hibernate 创建嵌套对象