Servlets 如何删除HTTP响应头?

Servlets 如何删除HTTP响应头?,servlets,servlet-filters,response-headers,Servlets,Servlet Filters,Response Headers,我遇到一种情况,其中一个响应头内容处置必须删除。因此,我考虑编写一个servlet过滤器来实现这一点。但是我意识到HttpServletResponse只有一个setHeader()方法,但没有删除它的方法。 如何执行此操作?您不能通过标准Servlet API删除之后的标题。你最好的办法就是阻止设置标题。您可以通过创建一个自定义实现来替换ServletResponse,该自定义实现在头名称为Content Disposition时跳过的作业 基本上: @Override public void

我遇到一种情况,其中一个响应头
内容处置
必须删除。因此,我考虑编写一个servlet过滤器来实现这一点。但是我意识到
HttpServletResponse
只有一个
setHeader()
方法,但没有删除它的方法。
如何执行此操作?

您不能通过标准Servlet API删除之后的标题。你最好的办法就是阻止设置标题。您可以通过创建一个自定义实现来替换
ServletResponse
,该自定义实现在头名称为
Content Disposition
时跳过的作业

基本上:

@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模式即可运行。

这可能与Servlet API不兼容,但将该值设置为null在GlassFish 4上有效,可能在Tomcat上也有效,因为GlassFish下面就是这个值

我们确实需要更新ServletAPI规范,以便添加一个允许删除头的方法,或者正式支持使用带有null值的setHeader


这一点很重要的一个例子是,如果您在web应用程序上使用安全约束(SSL/TLS),那么静态资源缓存会变得复杂,因为容器会自动添加头以防止缓存(您可以尝试在Tomcat/GlassFish上使用disableProxyCaching和securePagesWithPragma禁用)。我已经有了一个用于缓存控制的servlet过滤器,它对非安全内容非常有效,因此我希望将缓存控制都放在一个地方,只需将Prama和cache control设置为null即可清除任何容器添加的头。

这对我使用Spring 4不起作用。我试图去掉Expires响应头。每一页。像这样:

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));
    }
}
公共类AppConfig实现WebApplicationInitializer{
私有静态最终字符串DISPATCHER\u SERVLET\u NAME=“DISPATCHER”;
私有静态最终字符串调度程序_SERVLET_映射=“/”;
@凌驾
启动时公共void(ServletContext ServletContext)引发ServletException{
AnnotationConfigWebApplicationContext rootContext=新的AnnotationConfigWebApplicationContext();
register(AppContext.class);
ServletRegistration.Dynamic dispatcher=servletContext.addServlet(dispatcher_SERVLET_NAME,new DispatcherServlet(rootContext));
dispatcher.setLoadOnStartup(1);
addMapping(dispatcher\u SERVLET\u映射);
EnumSet dispatcherTypes=EnumSet.of(DispatcherType.REQUEST,DispatcherType.FORWARD);
FilterRegistration.Dynamic noCache=servletContext.addFilter(“noCacheFilter”,new CachingFilter());
addMappingForUrlPatterns(dispatcherTypes,true,“/*”;
addListener(新的ContextLoaderListener(rootContext));
}
}

正在为Expires和缓存控制调用setHeader(),但我无法覆盖Expires筛选器值或缓存控制值。我可以添加到缓存控制值。如果我在缓存控件上调用setHeader,它将变成一个值数组。但是我需要删除标题。

作为其他响应。在设置完头之后,没有办法删除头,至少不是标准的(glassfish允许清除头,将其值设置为null)。因此,在一天结束时,你有两个选择:

  • 使用
    response.Reset()
    重置响应-这将有效地删除所有头和所有缓冲数据,这取决于您的情况,是一个很好的选择(在我的情况下是在验证错误之后)。如果响应已经提交,您将得到一个IllegalStateException

  • 将标题设置为空字符串,显然这不会删除标题。但是http规范在接受编码、TE(传输编码)和主机头中只有一些定义和空值,因此根据您的需要,您可以在应用程序层中控制这些定义


  • 尝试阻止“服务器”头时,此方法失败。我想这是由容器设置的。@itsraja:的确如此。您需要在服务器自己的配置中控制它。在
    chain.doFilter()
    后面的整个过程中,上述过滤器仅控制webapp设置的标题。它不控制在此之前或之后设置的标题。顺便说一句,这很有道理:)我们可能也应该重写
    addHeader(字符串名称,字符串值)
    。@Milanka:有6个。只要覆盖你代码库中使用的任何东西,对我有用。只是要确保先运行这个过滤器。在我的例子中,在configure方法中的WebSecurity配置适配器中,作为第一个筛选器:httpSecurity.addFilterBefore(HeaderUnsetFilter(),HeaderWriterFilter.class);