如何删除HTTP响应头?

40

我遇到这样一种情况,需要删除其中一个响应头Content-Disposition,所以我想编写一个Servlet过滤器来实现。但是我发现HttpServletResponse只有一个setHeader()方法而没有删除该头的方法。 我该怎么做?

4个回答

57

按照标准的Servlet API,您无法在之后删除请求头。您最好的选择是仅仅防止设置该请求头。您可以创建一个Filter,它将ServletResponse替换为自定义HttpServletResponseWrapper实现,每当请求头名称为Content-Disposition时跳过setHeader()的任务。

基本上:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) {
        public void setHeader(String name, String value) {
            if (!name.equalsIgnoreCase("Content-Disposition")) {
                super.setHeader(name, value);
            }
        }
    });
}

只需将该过滤器映射到感兴趣的URL模式即可使其运行。


当尝试防止“Server”标头时,此方法会失败。我认为它是由容器设置的。 - itsraja
1
@itsraja:确实如此。您需要在服务器自己的配置中进行控制。上面介绍的过滤器仅控制chain.doFilter()后整个过程中Web应用程序设置的标头。它不控制在此之前或之后设置的标头。顺便说一下,这很有道理 :) - BalusC
7
也许还应该覆盖 addHeader(String name, String value) 方法。 - Milanka
1
@Milanka:它们有6个。只需覆盖您代码库中正在使用的任何内容即可。 - BalusC
1
对我有用。只需要确保该过滤器首先运行。在我的情况下,是在webSecurityConfigurationAdapter的configure方法中作为第一个过滤器: httpSecurity.addFilterBefore(HeaderUnsetFilter(), HeaderWriterFilter.class); - Recek
显示剩余6条评论

4
这可能不符合Servlet API标准,但在GlassFish 4上将值设置为null是可行的,并且可能在Tomcat上也有效,因为它是GlassFish下层的组件。
我们真的需要更新Servlet API规范,要么添加一个方法来允许删除头信息,要么正式支持使用setHeader并将其值设为null。
一个重要的例子是,如果您在Web应用程序上使用安全约束(SSL/TLS),那么静态资源缓存会因容器自动添加防止缓存的头信息而变得复杂(您可以尝试在Tomcat/GlassFish上使用disableProxyCaching和securePagesWithPragma来禁用)。我已经有了一个用于非安全内容的缓存控制Servlet过滤器,所以我想将所有缓存控制集中在一个地方,并简单地将Prama和Cache-Control设置为null以清除任何由容器添加的头信息。

3
像其他回答一样,没有办法在设置后删除头文件,至少不是标准的(glassfish允许通过将值设置为null来清除头文件)。所以最终你会有两个选择:
1.使用response.reset()重置响应 - 这有效地删除了所有标题和任何缓冲数据,根据你的情况可能是一个好的选择(在我的情况下是在身份验证验证错误之后) 。如果响应已经提交,则会出现IllegalStateException。
2.将头文件设置为空字符串,显然这并不会删除头文件。但是http规范仅对Accept-Encoding、TE(传输编码)和HOST头文件中的空值进行了一些定义,因此根据您的需求,您可以在应用程序层控制它。

1

使用Spring 4对我无效。我正在尝试删除所有页面的过期响应头,就像这样:

public class CachingFilter implements Filter {
    private final Log logger = LogFactory.getLog(getClass());

    public CachingFilter() {}
    public void destroy() {}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        logger.debug("doFilter()");
        chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) {
            public void setHeader(String name, String value) {
                logger.debug("setHeader(" + name + ","+value+")");

                if (!name.equalsIgnoreCase("Expires")) {
                    super.setHeader(name, value);
                }
            }
        });
    }

    public void init(FilterConfig fConfig) throws ServletException {}
}

这是我添加过滤器的方式:

public class AppConfig implements WebApplicationInitializer {
    private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
    private static final String DISPATCHER_SERVLET_MAPPING = "/";

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(AppContext.class);

        ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(rootContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping(DISPATCHER_SERVLET_MAPPING);

        EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);

        FilterRegistration.Dynamic noCache = servletContext.addFilter("noCacheFilter", new CachingFilter());
        noCache.addMappingForUrlPatterns(dispatcherTypes, true, "/*");

        servletContext.addListener(new ContextLoaderListener(rootContext));
    }
}

setHeader()被调用用于Expires和Cache-Control,但我无法覆盖Expires过滤器值或Cache-Control值。我可以添加到Cache-Control值。如果我在Cache-Control上调用setHeader,则会变成一个值数组。但我需要删除标题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接