为什么在 Spring 中有两种处理静态资源的方法(addResourceHandlers 和容器的默认 Servlet")? [英] Why are there 2 ways to handle static resources in Spring (addResourceHandlers and the container's Default Servlet")?

查看:69
本文介绍了为什么在 Spring 中有两种处理静态资源的方法(addResourceHandlers 和容器的默认 Servlet")?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am new to Spring. I noticed that when handling static resources, there are two options available:

选项 1:

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

If Spring's DispatcherServlet is mapped to / with the below code, which makes it the "Default Servlet", it's possible to map certain static resources to Spring handlers with RequestMapping annotation (overriding the AbstractAnnotationConfigDispatcherServletInitializer class):

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

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

Then we can still enable the container's "Default Servlet" to handle those static resources whose URL pattern is not covered by Spring request mapping (overriding the WebMvcConfigurerAdapter class):

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

这基本上使用 servlet 容器的默认 Servlet"作为 catch-all 来处理所有的静态资源 missed 由 Spring 的 DispatcherServlet 提供.

This basically uses the servlet container's "Default Servlet" as the catch-all to handle all the static resources missed by Spring's DispatcherServlet.

选项 2:

(覆盖 WebMvcConfigurerAdapter 类)

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

<小时>

  • 为什么有两种选择?
  • 这些方法之间的主要区别是什么?
  • 还有其他选择吗?
  • 我通常选择选项 2 是因为我想坚持使用 Spring,但我知道这不是一个强有力的理由.

    I usually take option 2 because I want to stick to Spring, but I know that's not a strong reason.

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

    Some reference related to static resources handling:

    加 1

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

    It seems option 2 provides much more flexibility regarding the resource mapping. And even resources within WEB-INF folder can be mapped.

    推荐答案

    这里有一个具体的例子 退回到默认"Servlet 以提供资源 不适用.

    Here is a concrete example of when Falling Back On the "Default" Servlet To Serve Resources is not applicable.

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

    This is a typical implementation of the above approach:

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

    然而,当前在 Spring 4 中处理 404 错误的最佳实践似乎是使用 setThrowExceptionIfNoHandlerFound:

    However, the current best practice for handling 404 errors in Spring 4 appears to be to use setThrowExceptionIfNoHandlerFound:

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

    不幸的是,根据 DispatcherServlet:

    注意如果 DefaultServletHttpRequestHandler 被使用,然后请求将始终被转发到默认的 servlet 和NoHandlerFoundException 在这种情况下永远不会被抛出.

    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 如链接所示answer) 解析为我的自定义notFoundPage".

    Indeed, this is the case. Combining both of the above approaches does not result in a NoHandlerFoundException being triggered, and this in turn prevents my 404 custom error page from resolving. Now, if I were to comment out my configureDefaultServletHandling method, the NoHandlerFoundException is thrown and my error handling (via @ControllerAdvice as shown in the linked answer) resolves to my custom 'notFoundPage'.

    不幸的是,这意味着我的静态资源(即default.css")没有被解析:

    Unfortunately, this now means that my static resources (i.e., 'default.css') are not resolved:

    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 方法.

    I do not see any way to reconcile these two approaches so that they will not interfere with each other. My conclusion is that the "Default Servlet" approach is not appropriate for serving static resources in this case, which leaves us with the addResourceHandlers method.

    使用 addResourceHandlers 方法是:

    Among the benefits of using the addResourceHandlers method are:

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

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

    Also see this answer for a more complicated example of how handling static resources with the default servlet can cause unwanted side effects.

    这篇关于为什么在 Spring 中有两种处理静态资源的方法(addResourceHandlers 和容器的默认 Servlet")?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆