使用 Spring Boot 到达静态内容时如何添加响应标头?

Posted

技术标签:

【中文标题】使用 Spring Boot 到达静态内容时如何添加响应标头?【英文标题】:How to add response header when reaching static content using Spring Boot? 【发布时间】:2017-10-02 11:34:36 【问题描述】:

向控制器添加响应头很简单,例如:

@RequestMapping(value = "/test", method = RequestMethod.GET)
public String test(HttpServletResponse response)

 response.setHeader("specialheader", "Special Header");
 return "ok";

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

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

这个想法来自link。

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

如何向服务器发出的每个响应添加通用响应标头,包括静态文件的响应?

【问题讨论】:

【参考方案1】:

注意:Spring 2.x 可能有更好的选择。

在我的情况下 (1.5.x),FilterRegistrationBean 方法没有向错误页面添加额外的标题;因此是另一种选择。

如果您希望将此类标头应用于所有静态内容,包括错误页面常规静态内容(例如,作为安全审计/漏洞评估的一部分),您可能需要遵循复合方法。

首先,一个简单的实用程序类/方法来保持标题添加统一:

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");
    

这会将上述标头添加到标准 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;
    

这会将上述标题添加到错误页面

    @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 Security 级别应用标头,它们将不会出现在 静态 内容中,例如欢迎页面(基本/索引 HTML)和错误页面。 (除非您以某种方式配置/修改 Spring Security 以包含静态路径 - 这当然是不必要的,并且可能会影响性能) 如果您仅使用 ResourceHttpRequestHandler 来注入标头,它们将不会出现安全拦截控制器响应或(更重要的是)错误页面上。 在HandlerInterceptorAdapter 中,我尝试在preHandle()afterCompletion() 上配置标题;然而,它们并没有被应用于某些场景——尤其是。用于错误页面。

【讨论】:

【参考方案2】:

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

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

【讨论】:

以上是关于使用 Spring Boot 到达静态内容时如何添加响应标头?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 jar 外部的 spring boot 提供静态内容?

带有静态内容的 Spring Boot 项目在运行 jar 时生成 404

如何在 Spring Boot 2.2.6 中提供静态内容?

Spring-Boot Jersey:允许 Jersey 提供静态内容

Spring Boot devtools - 静态内容重新加载在 IntelliJ 中不起作用

Spring Boot 2 和 Security With JWT 无法提供 Angular 构建的静态内容