Filter 自定义Servlet筛选器未应用于所有资源

Filter 自定义Servlet筛选器未应用于所有资源,filter,servlet-filters,tomcat9,Filter,Servlet Filters,Tomcat9,我创建了一个简单的过滤器类,它向所有请求的资源添加了一些响应头。 我已经创建了一个jar文件,并将其添加到tomcat lib文件夹中。此外,该过滤器还添加到web.xml中,用于url映射/* 当我请求应用程序的页面时,我可以看到过滤器被调用,因为sysout语句被正确打印,但标题仅被添加到一些资产中。 我很困惑,为什么它只被添加到一些资产中,而不是所有资产中 过滤类如下所示 package com.headers.config; import java.io.IOException; im

我创建了一个简单的过滤器类,它向所有请求的资源添加了一些响应头。 我已经创建了一个jar文件,并将其添加到tomcat lib文件夹中。此外,该过滤器还添加到web.xml中,用于url映射/*

当我请求应用程序的页面时,我可以看到过滤器被调用,因为sysout语句被正确打印,但标题仅被添加到一些资产中。 我很困惑,为什么它只被添加到一些资产中,而不是所有资产中

过滤类如下所示

package com.headers.config;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MySecurityHeadersFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
} 

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {

chain.doFilter(request, response);

HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpResp = (HttpServletResponse) response;

httpResp.addHeader("Content-Security-Policy", "default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';base-uri 'self';form-action 'self';");
httpResp.addHeader("Expect-CT", "max-age=86400, enforce, report-uri=https://"+ httpReq.getHeader("host").trim() +"/bham/user/reportCT");
httpResp.addHeader("Feature-Policy", "vibrate 'none'; geolocation 'none';");
httpResp.addHeader("Referrer-Policy", "no-referrer-when-downgrade");

System.out.println("Response Headers: "+((HttpServletResponse) response).getHeaderNames());
}

@Override
public void destroy() {
}
}

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.headers.config</groupId>
<artifactId>MySecurityHeadersFilter</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>MySecurityHeadersFilter Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
    <!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
<build>
    <finalName>MySecurityHeadersFilter</finalName>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>
</project>

对我来说毫无意义,过滤器适用于所有内容,请求可能没有真正到达服务器,您是否看到浏览器开发人员工具栏中的调用?它返回200吗

一旦提交响应,就不能设置头

您的筛选器对某些请求有效而对其他请求无效的原因是,某些请求在筛选器可以添加标头之前提交响应,而有些请求则不能

如果移动
chain.doFilter(请求、响应)在设置头的代码之后调用,过滤器应应用于所有内容


如果要确保后续请求不会更改头,您有几个选项。提交响应是最简单的,但它是一个相当迟钝的工具,可能会破坏一些下游请求(例如,尝试执行
RequestDispatcher.forward()的任何请求)
。更好的解决方案是包装响应,拦截所有更改标头的调用,并过滤掉不需要的调用。

对于可能面临相同问题的任何人,有效的响应包装类如下所示

import java.io.*;
import javax.servlet.http.*;

public class HeaderResponseWrapper extends HttpServletResponseWrapper {
private CharArrayWriter writer;

public HeaderResponseWrapper(HttpServletResponse response) {
    super(response);
    writer = new CharArrayWriter();
}
}
doFilter方法也将更改

HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpResp = (HttpServletResponse) response;

HeaderResponseWrapper headerResponseWrapper = new HeaderResponseWrapper(httpResp);

headerResponseWrapper.addHeader("Content-Security-Policy", "default-src 'self'");
chain.doFilter(request, headerResponseWrapper);

是的,我可以从catalina.out日志中看到对过滤器的调用,也可以看到开发人员工具中的调用。可能是您有其他过滤器吗?您使用的是spring或类似的工具吗?但这不应该导致它被添加到某些资产,而不是其他资产。例如1.js有标题,但2.js没有,这就是我所做的无法理解。它们都属于同一个路径。如果要确保向服务器发出请求,请将新日期()放入浏览器中,JavaScript通常会缓存在浏览器中在JSP中的资源请求中。我也为每个请求清除了浏览器中的缓存,但在新请求中仍然存在相同的问题。过滤器的源代码please@MarkThomas我已经添加了过滤代码和pom.xml。还有,我如何使用request.getHeaderNames方法?如果我试图在我当前的类中使用它,它会给出错误提示方法不存在。我需要更改servlet api的版本吗?您好,Mark,我已经尝试将chain.doFilter(请求,响应);作为方法的最后一行移动,但这也没有帮助。当您说包装响应时,是否有一个示例?我已经创建了一个HttpServletResponseWrapper,它现在正在工作
import java.io.*;
import javax.servlet.http.*;

public class HeaderResponseWrapper extends HttpServletResponseWrapper {
private CharArrayWriter writer;

public HeaderResponseWrapper(HttpServletResponse response) {
    super(response);
    writer = new CharArrayWriter();
}
}
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpResp = (HttpServletResponse) response;

HeaderResponseWrapper headerResponseWrapper = new HeaderResponseWrapper(httpResp);

headerResponseWrapper.addHeader("Content-Security-Policy", "default-src 'self'");
chain.doFilter(request, headerResponseWrapper);