如何在使用 Spring 引导到达静态内容时添加响应 header?

How to add response header when reaching static content using Spring Boot?

向控制器添加响应 header 非常简单,如:

@RequestMapping(value = "/test", method = RequestMethod.GET)
public String test(HttpServletResponse response)
{
 response.setHeader("specialheader", "Special Header");
 return "ok";
}

但当用户尝试访问服务器上的静态内容(如 .css 文件)时情况并非如此,我显然不想为每个文件创建端点。

所以我尝试使用实现 ResponseBodyAdvice 的新 class (@ControllerAdvice),并覆盖 'beforeBodyWrite' 函数,我得到了每个具有端点的查询的预期结果。

这个想法来源于此link

但是当我尝试访问服务器上的一个简单的 .css 文件时,不会调用 ControllerAdvice,因此文件在浏览器中打开时没有设置预期的 headers。

如何向服务器发出的每个响应(包括静态文件的响应)添加一般响应 header?

您必须应用过滤器。这将应用于每个 HTTP 请求的响应。

您可以在这里找到确切的答案: How to add a filter class in Spring Boot?

注: Spring 2.x.

可能有更好的选择

在我的案例 (1.5.x) 中,FilterRegistrationBean 方法没有向错误页面添加额外的 header;因此是另一种选择。

如果您希望将此类 header 应用于 所有静态内容 ,包括错误页面 常规静态内容(例如安全 audit/vulnerability 评估的一部分),您可能必须遵循复合方法。

首先,一个简单的实用程序 class/method 来保持 header 添加的统一:

import javax.servlet.http.HttpServletResponse;

public class SecurityUtils {
    public static void addHtmlSecurityHeaders(HttpServletResponse response) {
        // some example content-security related headers
        response.setHeader("X-Content-Type-Options", "nosniff");
        response.setHeader("X-Frame-Options", "deny");
    }
}

这将 headers 添加到标准 static/ 资源(由 this SO answer 提供):

    @Bean
    public ResourceHttpRequestHandler staticHandler() {
        ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler() {
            @Override
            public void setHeaders(HttpServletResponse response, Resource resource, MediaType mediaType) throws IOException {
                SecurityUtils.addHtmlSecurityHeaders(response);
                super.setHeaders(response, resource, mediaType);
            }
        };
        handler.setLocations(Collections.singletonList(new ClassPathResource("static/")));
        return handler;
    }

    @Bean
    public SimpleUrlHandlerMapping staticMapping() {
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        mapping.setOrder(Integer.MAX_VALUE - 2);
        Properties urlProperties = new Properties();
        urlProperties.put("/**", "staticHandler");
        mapping.setMappings(urlProperties);
        return mapping;
    }

这会将 header 秒添加到 错误页面:

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {

            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                registry.addInterceptor(new HandlerInterceptorAdapter() {
                    @Override
                    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
                        SecurityUtils.addHtmlSecurityHeaders(response);
                    }
                });
            }

            // .. more overrides
        };
    }

另外,关于其他方法的一些观察:

  • 如果您在 Spring 安全级别应用 headers,它们将不会出现在 static 内容中,例如欢迎页面 (base/index HTML) 和错误页面。 (除非你以某种方式 configure/modify Spring 安全性也包括静态路径 - 这当然是不必要的,并且可能会影响性能)
  • 如果您仅使用 ResourceHttpRequestHandler 注入 header,它们将不会出现 Security-intercepted 控制器响应或(更重要的是)错误页面。
  • HandlerInterceptorAdapter 中,我尝试在 preHandle()afterCompletion() 上配置 header;然而,他们并没有被应用于某些场景——尤其是。对于错误页面。