# SpringBoot Web中過濾器Filter的使用方法
## 目錄
- [一、過濾器(Filter)概述](#一過濾器filter概述)
- [1.1 什么是過濾器](#11-什么是過濾器)
- [1.2 過濾器與攔截器的區別](#12-過濾器與攔截器的區別)
- [1.3 過濾器的應用場景](#13-過濾器的應用場景)
- [二、SpringBoot中Filter的實現方式](#二springboot中filter的實現方式)
- [2.1 實現Filter接口](#21-實現filter接口)
- [2.2 使用@WebFilter注解](#22-使用webfilter注解)
- [2.3 通過FilterRegistrationBean注冊](#23-通過filterregistrationbean注冊)
- [三、Filter的生命周期與核心方法](#三filter的生命周期與核心方法)
- [3.1 init()初始化方法](#31-init初始化方法)
- [3.2 doFilter()過濾邏輯](#32-dofilter過濾邏輯)
- [3.3 destroy()銷毀方法](#33-destroy銷毀方法)
- [四、Filter的配置詳解](#四filter的配置詳解)
- [4.1 URL模式匹配](#41-url模式匹配)
- [4.2 過濾器執行順序](#42-過濾器執行順序)
- [4.3 初始化參數配置](#43-初始化參數配置)
- [五、實戰案例](#五實戰案例)
- [5.1 請求日志記錄過濾器](#51-請求日志記錄過濾器)
- [5.2 權限驗證過濾器](#52-權限驗證過濾器)
- [5.3 XSS防護過濾器](#53-xss防護過濾器)
- [5.4 跨域處理過濾器](#54-跨域處理過濾器)
- [六、高級應用](#六高級應用)
- [6.1 過濾器鏈工作原理](#61-過濾器鏈工作原理)
- [6.2 異步請求處理](#62-異步請求處理)
- [6.3 異常處理機制](#63-異常處理機制)
- [七、常見問題與解決方案](#七常見問題與解決方案)
- [7.1 過濾器不生效問題](#71-過濾器不生效問題)
- [7.2 執行順序問題](#72-執行順序問題)
- [7.3 性能優化建議](#73-性能優化建議)
- [八、總結與最佳實踐](#八總結與最佳實踐)
## 一、過濾器(Filter)概述
### 1.1 什么是過濾器
過濾器(Filter)是Java Web開發中的核心組件之一,它可以在請求到達Servlet之前或響應返回客戶端之前對HTTP請求和響應進行預處理和后處理。在Spring Boot應用中,過濾器仍然扮演著重要角色,主要用于處理與業務邏輯無關的橫切關注點。
過濾器的主要特點包括:
- 在請求到達Controller前進行預處理
- 在響應返回客戶端前進行后處理
- 可以攔截多個請求,實現代碼復用
- 通過配置可以靈活控制過濾范圍
### 1.2 過濾器與攔截器的區別
| 特性 | 過濾器(Filter) | 攔截器(Interceptor) |
|--------------|----------------------------------------|---------------------------------------|
| 作用范圍 | Servlet規范,任何Web框架可用 | Spring MVC特有 |
| 執行時機 | 在DispatcherServlet之前 | 在DispatcherServlet之后,Controller之前|
| 依賴 | 依賴Servlet容器 | 依賴Spring框架 |
| 獲取上下文 | 只能獲取Servlet API對象 | 可以獲取Spring上下文和業務對象 |
| 使用場景 | 字符編碼、跨域處理、XSS防護等 | 權限驗證、日志記錄、參數預處理等 |
### 1.3 過濾器的應用場景
1. **安全相關**:XSS防護、CSRF防護、權限驗證
2. **日志記錄**:請求/響應日志、訪問統計
3. **性能監控**:接口耗時統計、QPS監控
4. **編碼處理**:統一字符編碼設置
5. **跨域處理**:CORS跨域資源共享配置
6. **數據壓縮**:響應內容GZIP壓縮
7. **緩存控制**:HTTP緩存頭設置
## 二、SpringBoot中Filter的實現方式
### 2.1 實現Filter接口
這是最基礎的實現方式,創建一個類實現`javax.servlet.Filter`接口:
```java
import javax.servlet.*;
import java.io.IOException;
public class CustomFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化邏輯
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 前置處理
System.out.println("Before filter processing");
// 放行請求
chain.doFilter(request, response);
// 后置處理
System.out.println("After filter processing");
}
@Override
public void destroy() {
// 銷毀邏輯
}
}
Spring Boot支持Servlet 3.0的@WebFilter
注解,可以簡化配置:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/*", filterName = "customFilter")
public class CustomFilter implements Filter {
// 實現方法同上
}
還需要在啟動類添加@ServletComponentScan
注解:
@SpringBootApplication
@ServletComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
這是Spring Boot推薦的方式,提供了更靈活的配置:
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<CustomFilter> customFilterRegistration() {
FilterRegistrationBean<CustomFilter> registration =
new FilterRegistrationBean<>();
registration.setFilter(new CustomFilter());
registration.addUrlPatterns("/*");
registration.setOrder(1); // 設置執行順序
registration.setName("customFilter");
return registration;
}
}
init
方法在過濾器實例創建后立即執行,用于初始化操作:
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 獲取初始化參數
String param = filterConfig.getInitParameter("paramName");
// 初始化資源
this.someResource = initResource();
log.info("Filter initialized with param: {}", param);
}
doFilter
是過濾器的核心方法,處理請求和響應:
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 1. 前置處理
long startTime = System.currentTimeMillis();
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 2. 業務邏輯處理
if (shouldFilter(httpRequest)) {
// 可以修改請求或響應
CustomRequestWrapper wrappedRequest = new CustomRequestWrapper(httpRequest);
// 繼續過濾器鏈
chain.doFilter(wrappedRequest, response);
} else {
chain.doFilter(request, response);
}
// 3. 后置處理
long duration = System.currentTimeMillis() - startTime;
log.info("Request {} processed in {} ms", httpRequest.getRequestURI(), duration);
}
destroy
在Web應用關閉時調用,用于釋放資源:
@Override
public void destroy() {
// 釋放資源
if (this.someResource != null) {
this.someResource.close();
}
log.info("Filter destroyed");
}
Spring Boot支持多種URL匹配模式:
registration.addUrlPatterns(
"/api/*", // 匹配/api路徑下的所有請求
"*.html", // 匹配所有html文件
"/admin/**", // 匹配/admin及其子路徑
"/public/resources/*.css" // 匹配特定資源
);
通過setOrder
方法控制執行順序,值越小優先級越高:
@Bean
public FilterRegistrationBean<FilterA> filterA() {
FilterRegistrationBean<FilterA> reg = new FilterRegistrationBean<>();
reg.setOrder(1); // 最先執行
// ...
}
@Bean
public FilterRegistrationBean<FilterB> filterB() {
FilterRegistrationBean<FilterB> reg = new FilterRegistrationBean<>();
reg.setOrder(2); // 其次執行
// ...
}
可以通過兩種方式配置初始化參數:
@WebFilter(
urlPatterns = "/*",
initParams = {
@WebInitParam(name = "param1", value = "value1"),
@WebInitParam(name = "param2", value = "value2")
}
)
registration.addInitParameter("param1", "value1");
registration.addInitParameter("param2", "value2");
在Filter中通過FilterConfig獲?。?/p>
String value = filterConfig.getInitParameter("param1");
public class RequestLoggingFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(RequestLoggingFilter.class);
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 記錄請求信息
String requestURI = httpRequest.getRequestURI();
String method = httpRequest.getMethod();
String queryString = httpRequest.getQueryString();
String clientIP = httpRequest.getRemoteAddr();
log.info("Request: {} {}?{}, IP: {}", method, requestURI, queryString, clientIP);
long startTime = System.currentTimeMillis();
chain.doFilter(request, response);
long duration = System.currentTimeMillis() - startTime;
log.info("Response: {} completed in {} ms", requestURI, duration);
}
// init和destroy方法省略
}
public class AuthFilter implements Filter {
private List<String> excludeUrls = Arrays.asList("/login", "/public/");
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String path = httpRequest.getRequestURI().substring(
httpRequest.getContextPath().length());
// 排除不需要驗證的URL
if (isExcluded(path)) {
chain.doFilter(request, response);
return;
}
// 檢查認證信息
String token = httpRequest.getHeader("Authorization");
if (!validateToken(token)) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token");
return;
}
chain.doFilter(request, response);
}
private boolean isExcluded(String path) {
return excludeUrls.stream().anyMatch(path::startsWith);
}
private boolean validateToken(String token) {
// 實現token驗證邏輯
return true;
}
}
public class XssFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new XssRequestWrapper((HttpServletRequest) request), response);
}
}
public class XssRequestWrapper extends HttpServletRequestWrapper {
public XssRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
return cleanXss(super.getParameter(name));
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if (values == null) return null;
return Arrays.stream(values).map(this::cleanXss).toArray(String[]::new);
}
private String cleanXss(String value) {
if (value == null) return null;
// 實現XSS清理邏輯
return value.replaceAll("<", "<").replaceAll(">", ">");
}
}
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 設置CORS頭
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
httpResponse.setHeader("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS");
httpResponse.setHeader("Access-Control-Max-Age", "3600");
httpResponse.setHeader("Access-Control-Allow-Headers",
"Content-Type, Authorization, X-Requested-With");
// 對OPTIONS請求直接返回
if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) {
httpResponse.setStatus(HttpServletResponse.SC_OK);
return;
}
chain.doFilter(request, response);
}
}
Spring Boot中的過濾器鏈執行流程:
doFilter
方法被調用chain.doFilter()
進入Servlet對于異步請求,需要特殊處理:
public class AsyncFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (request.isAsyncSupported()) {
request.setAttribute("ASYNC_SUPPORTED", true);
}
// 包裝響應以支持異步
AsyncResponseWrapper wrappedResponse = new AsyncResponseWrapper(
(HttpServletResponse) response);
try {
chain.doFilter(request, wrappedResponse);
} finally {
if (!request.isAsyncStarted()) {
wrappedResponse.finish();
}
}
}
}
過濾器中的異常處理策略:
public class ExceptionHandlingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (Exception e) {
handleException((HttpServletRequest) request,
(HttpServletResponse) response, e);
}
}
private void handleException(HttpServletRequest request,
HttpServletResponse response,
Exception ex) throws IOException {
// 根據異常類型返回不同的錯誤響應
if (ex instanceof AuthenticationException) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ex.getMessage());
} else {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Server error");
}
}
}
可能原因及解決方案:
未正確注冊:
@Component
或@WebFilter
+@ServletComponentScan
FilterRegistrationBean
顯式注冊URL模式不匹配:
urlPatterns
是否包含目標路徑/*
測試是否匹配所有請求順序問題:
chain.doFilter()
控制執行順序的方法:
使用@Order
注解:
@Component
@Order(1)
public class FilterA implements Filter { ... }
使用FilterRegistrationBean
的setOrder
方法:
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
實現Ordered
接口:
public class FilterB implements Filter, Ordered {
@Override
public int getOrder() { return 2; }
}
if (!needsFiltering(request)) {
chain.doFilter(request, response);
return;
}
適用場景:
實現方式對比:
方式 | 優點 | 缺點 |
---|---|---|
實現Filter接口 | 簡單直接 | 配置不夠靈活 |
@WebFilter注解 | 配置簡潔 | 順序控制有限 |
FilterRegistrationBean | 高度可配置,功能強大 | 代碼量稍多 |
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。