在构建 Web 应用时,我们经常需要对请求进行拦截和处理,以实现诸如身份验证、授权、日志记录等功能。在 Spring Boot 中,为我们提供了两种强大的工具来实现这些功能:过滤器(Filter)和拦截器(Interceptor)。尽管这两者在某些方面的功能相似,它们在使用场景、处理层级和实现方式上却有所不同。在本文中,我们将详细介绍过滤器和拦截器的区别、各自的优势,以及如何在实际项目中使用这两种组件来处理请求。这将帮助您了解在不同情况下应该选择哪种组件来满足您的需求,以便更好地构建和维护您的 Web 应用。
在Spring Boot中,拦截器分为两类:
一种是对请求进来的url进行拦截,HandlerInterceptor接口;
一种是对发送出去的请求进行拦截,ClientHttpRequestInterceptor。
要创建一个请求拦截器,你需要执行以下步骤:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestTimingInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(RequestTimingInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
logger.info("{} {} took {} ms", request.getMethod(), request.getRequestURI(), duration);
}
}
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):在请求处理之前被调用。如果返回true,则继续处理请求;如果返回false,则中止请求。
postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):在请求处理之后,但在视图渲染之前被调用。可以对模型和视图进行进一步处理。
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):在请求处理完成且视图渲染之后被调用。可以进行资源清理等操作。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RequestTimingInterceptor());
}
}
在addInterceptors方法中,你可以使用registry.addInterceptor(yourInterceptor).addPathPatterns("/**")指定拦截器应用于哪些URL模式。
这样,每次满足指定URL模式的请求时,Spring Boot就会调用你的拦截器。
对于服务间调用,你可以使用ClientHttpRequestInterceptor接口来拦截和处理发送出去的请求。这通常用于处理微服务之间的通信,例如添加认证信息、自定义请求头等。
要实现一个发送出去的请求拦截器,请按照以下步骤操作:
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import java.io.IOException;
public class CustomHeaderInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
request.getHeaders().set("Custom-Header", "CustomHeaderValue");
return execution.execute(request, body);
}
}
在这个类中,覆盖并实现intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)方法。在这个方法中,你可以访问和修改请求对象,然后调用execution.execute(request, body)继续执行请求。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
List interceptors = new ArrayList<>();
interceptors.add(new CustomHeaderInterceptor());
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
}
现在,每当你使用 RestTemplate 发起请求时,CustomHeaderInterceptor 将被调用。拦截器会在请求中添加一个名为 "Custom-Header" 的自定义请求头,值为 "CustomHeaderValue"。
HandlerInterceptor 和 ClientHttpRequestInterceptor 都是 Spring 框架中的拦截器,但它们的作用和使用场景不同。下面是它们之间的主要区别:
作用范围:
使用场景:
接口定义:
简而言之,HandlerInterceptor 主要关注应用内的请求处理,而 ClientHttpRequestInterceptor 主要关注应用间的通信。根据你的需求和使用场景,可以选择使用合适的拦截器来实现自定义的请求处理逻辑。
特征 | HandlerInterceptor | ClientHttpRequestInterceptor |
---|---|---|
作用范围 | 拦截接收到的 HTTP 请求 | 拦截使用 RestTemplate 或 WebClient 发送的 HTTP 请求 |
使用场景 | 身份验证、授权、日志记录、CORS 等应用内请求处理功能 | 添加认证信息、自定义请求头、请求数据处理、重试策略等服务间通信功能 |
接口定义 | org.springframework.web.servlet.HandlerInterceptor | org.springframework.http.client.ClientHttpRequestInterceptor |
需要实现的方法 | preHandle、postHandle 和 afterCompletion | intercept |
这个表格概括了 HandlerInterceptor
和 ClientHttpRequestInterceptor
之间的主要区别。根据你的需求和使用场景,可以选择使用合适的拦截器来实现自定义的请求处理逻辑。
在 Spring Boot 中,过滤器(Filter)是用于在 Servlet 容器级别拦截和处理 HTTP 请求的组件。它们通常用于实现诸如身份验证、授权、日志记录、请求和响应的数据转换等功能。过滤器位于整个请求处理链的最前端,因此在请求到达 Spring 应用的任何其他组件之前,都会先经过过滤器处理。
要在 Spring Boot 中创建一个过滤器,你需要执行以下步骤:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@WebFilter(urlPatterns = "/*")
public class RequestTimingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
long startTime = System.currentTimeMillis();
try {
chain.doFilter(request, response);
} finally {
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
HttpServletRequest httpRequest = (HttpServletRequest) request;
System.out.println(String.format("%s %s took %d ms", httpRequest.getMethod(), httpRequest.getRequestURI(), duration));
}
}
@Override
public void destroy() {
}
}
要将此过滤器添加到 Spring Boot 应用中,请将其注册为 Bean:
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 requestTimingFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new RequestTimingFilter());
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
}
现在,每次收到请求时,RequestTimingFilter 都会被调用。过滤器将记录请求的开始时间,然后在请求完成后计算处理时间,并将其输出到控制台。
过滤器(Filter)和拦截器(Interceptor)在某些方面的功能确实相似,但它们在使用场景、处理层级和实现方式上有所不同。以下是过滤器和拦截器之间的主要区别和各自的优势:
处理层级:
过滤器(Filter)基于 Java Servlet 规范,在 Servlet 容器级别处理请求。过滤器在整个请求处理链的最前端,因此在请求到达 Spring 应用的任何其他组件之前,都会先经过过滤器处理。
拦截器(Interceptor)是 Spring MVC 的一部分,用于处理 Spring 应用中接收到的请求。拦截器在 Spring 处理请求的过程中起作用,位于过滤器之后。
使用场景:
优势:
实现方式:
总的来说,过滤器和拦截器在功能上有一定的重叠,但它们的使用场景、处理层级和实现方式有所不同。选择使用过滤器还是拦截器取决于你的具体需求和场景。当你需要处理与框架无关的请求时,可以使用过滤器;当你需要实现与 Spring 框架相关的功能时,拦截器可能是更好的选择。
特征 | 过滤器(Filter) | 拦截器(Interceptor) |
---|---|---|
处理层级 | Servlet 容器级别 | Spring MVC 层级 |
使用场景 | 通用功能,如身份验证、授权、日志记录等 | 与 Spring 框架相关的功能,如身份验证、请求参数处理等 |
优势 | 处理任何 Web 应用的请求,更大的控制范围 | 紧密集成于 Spring MVC,可以访问 Spring 上下文和其他组件 |
实现接口 | javax.servlet.Filter | org.springframework.web.servlet.HandlerInterceptor 或 org.springframework.http.client.ClientHttpRequestInterceptor |
这个表格概括了过滤器(Filter)和拦截器(Interceptor)之间的主要区别。根据你的需求和使用场景,可以选择使用合适的组件来实现自定义的请求处理逻辑。
总之,过滤器(Filter)和拦截器(Interceptor)都是 Spring Boot 中强大的请求处理工具,它们分别适用于不同的场景和需求。通过对这两种组件的深入了解,我们可以根据具体需求选择使用过滤器还是拦截器,以实现优雅、高效的请求处理逻辑。在实际项目中,我们可能需要根据不同的功能和场景组合使用过滤器和拦截器,以充分发挥它们的优势。希望本文能够帮助您更好地理解过滤器和拦截器的区别与应用,从而为您的 Web 应用提供更为稳定和安全的请求处理方案。