我有一种情况,其中一个响应标头Content-Disposition
必须被删除。所以我想写一个servlet过滤器来做到这一点。但我意识到HttpServletResponse
只有一个setHeader()
方法,但没有删除它的方法。我怎样才能做到这一点?
4 回答
之后您不能通过标准 Servlet API 删除标头。您最好的选择是阻止设置标题。您可以通过创建一个Filter
替换 的ServletResponse
自定义实现来做到这一点,该实现在标题名称为 时HttpServletResponseWrapper
跳过的工作。setHeader()
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 下的内容。
我们确实需要更新 Servlet API 规范,以添加一个允许删除标头的方法,或者正式支持使用带有 null 值的 setHeader。
这很重要的一个示例是,如果您在 Web 应用程序上使用安全约束 (SSL/TLS),那么静态资源缓存会因为容器会自动添加标头以防止缓存而变得复杂(您可以尝试使用 disableProxyCaching 和Tomcat/GlassFish 上的securePagesWithPragma)。我已经有一个用于缓存控制的 servlet 过滤器,它非常适用于非安全内容,因此我想将缓存控制全部保存在一个地方,只需将 Prama 和 Cache-Control 设置为 null 即可清除任何容器添加的标头。
与其他回应一样。设置后无法删除标头,至少不是标准的(glassfish 可以清除标头,将其值设置为空)。因此,在一天结束时,您将有两个选择:
重置响应
response.reset()
- 这有效地删除了所有标题和任何缓冲数据,根据您的情况可能是一个不错的选择(在我的情况下是在身份验证验证错误之后)。如果响应已经提交,您将收到 IllegalStateException。将标头设置为空字符串,显然这不会删除标头。但是 http 规范在 Accept-Encoding、TE(传输编码)和 HOST 标头中只有一些定义和空值,因此您可以根据需要在应用程序层中控制它。
这对我使用 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));
}
}
为 Expires 和 Cache-Control 调用 setHeader(),但我无法覆盖 Expires 过滤器值或 Cache-Control 值。我可以添加到 Cache-Control 值。如果我在 Cache-Control 上调用 setHeader,它会变成一个值数组。但我需要删除标题。