spring boot的拦截器与过滤器介绍与对比

前言

在构建 Web 应用时,我们经常需要对请求进行拦截和处理,以实现诸如身份验证、授权、日志记录等功能。在 Spring Boot 中,为我们提供了两种强大的工具来实现这些功能:过滤器(Filter)和拦截器(Interceptor)。尽管这两者在某些方面的功能相似,它们在使用场景、处理层级和实现方式上却有所不同。在本文中,我们将详细介绍过滤器和拦截器的区别、各自的优势,以及如何在实际项目中使用这两种组件来处理请求。这将帮助您了解在不同情况下应该选择哪种组件来满足您的需求,以便更好地构建和维护您的 Web 应用。

拦截器

在Spring Boot中,拦截器分为两类:
一种是对请求进来的url进行拦截,HandlerInterceptor接口;
一种是对发送出去的请求进行拦截,ClientHttpRequestInterceptor。

HandlerInterceptor接口

要创建一个请求拦截器,你需要执行以下步骤:

  1. 创建一个类,实现org.springframework.web.servlet.HandlerInterceptor接口。
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):在请求处理完成且视图渲染之后被调用。可以进行资源清理等操作。

  1. 注册拦截器:要让Spring Boot知道你的拦截器,需要创建一个配置类,该类实现WebMvcConfigurer接口,并覆盖addInterceptors(InterceptorRegistry registry)方法,然后将拦截器实例添加到注册表中。
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接口

对于服务间调用,你可以使用ClientHttpRequestInterceptor接口来拦截和处理发送出去的请求。这通常用于处理微服务之间的通信,例如添加认证信息、自定义请求头等。

要实现一个发送出去的请求拦截器,请按照以下步骤操作:

  1. 创建一个类,实现org.springframework.http.client.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)继续执行请求。

  1. 创建一个配置类,将拦截器添加到RestTemplate或WebClient中。这两个类都是Spring框架中用于发起HTTP请求的客户端。
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的区别

HandlerInterceptor 和 ClientHttpRequestInterceptor 都是 Spring 框架中的拦截器,但它们的作用和使用场景不同。下面是它们之间的主要区别:

作用范围:

  • HandlerInterceptor 主要用于拦截处理 Spring 应用中接收到的 HTTP 请求。它允许你在请求处理之前、处理之后、以及视图渲染完成后执行自定义逻辑。
  • ClientHttpRequestInterceptor 主要用于拦截和处理 Spring 应用中使用 RestTemplate 或 WebClient 发送的 HTTP 请求。它让你在请求发送之前,对请求头、请求体等进行自定义处理。

使用场景:

  • HandlerInterceptor 通常用于身份验证、授权、日志记录、跨域资源共享(CORS)等应用内请求处理相关的功能。
  • ClientHttpRequestInterceptor 通常用于处理服务间通信,例如在请求头中添加认证信息、自定义请求头、请求数据处理、重试策略等。

接口定义:

  • HandlerInterceptor 是 org.springframework.web.servlet.HandlerInterceptor 接口,需要实现 preHandle、postHandle 和 afterCompletion 方法。
  • ClientHttpRequestInterceptor 是 org.springframework.http.client.ClientHttpRequestInterceptor 接口,需要实现 intercept 方法。

简而言之,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 中创建一个过滤器,你需要执行以下步骤:

  1. 创建一个类,实现 javax.servlet.Filter 接口。
  2. 在这个类中,覆盖并实现 init(FilterConfig filterConfig)、doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 和 destroy() 方法。
    init(FilterConfig filterConfig):初始化方法,在过滤器实例化时调用。
    doFilter(ServletRequest request, ServletResponse response, FilterChain chain):处理请求的核心方法。在这个方法中,你可以访问和修改请求和响应对象,并通过调用 chain.doFilter(request, response) 继续处理请求。
    destroy():销毁方法,在过滤器实例被销毁时调用。
  3. 注册过滤器:将过滤器作为一个 Bean 注册到 Spring 应用中。
    以下是一个简单的过滤器示例,用于记录每个请求的处理时间:
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 处理请求的过程中起作用,位于过滤器之后。

使用场景:

  • 过滤器(Filter)通常用于实现通用的、与框架无关的功能,如身份验证、授权、日志记录、请求和响应的数据转换等。
  • 拦截器(Interceptor)通常用于实现与 Spring 框架相关的功能,如验证用户身份、授权、请求参数处理、异常处理等。

优势:

  • 过滤器(Filter)可以处理任何 Web 应用的请求,不局限于 Spring。过滤器允许你在请求到达任何框架组件之前对其进行处理,提供了更大的控制范围。
  • 拦截器(Interceptor)更紧密地集成在 Spring MVC 中,因此可以更方便地使用 Spring 提供的功能。拦截器可以访问 Spring 上下文,让你能够轻松地使用其他 Spring 组件和服务。

实现方式:

  • 过滤器(Filter)需要实现 javax.servlet.Filter 接口,并实现 init、doFilter 和 destroy 方法。
  • 拦截器(Interceptor)需要实现 HandlerInterceptor 接口(对于请求拦截)或 ClientHttpRequestInterceptor 接口(对于客户端请求拦截),并实现相应的方法。

总的来说,过滤器和拦截器在功能上有一定的重叠,但它们的使用场景、处理层级和实现方式有所不同。选择使用过滤器还是拦截器取决于你的具体需求和场景。当你需要处理与框架无关的请求时,可以使用过滤器;当你需要实现与 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 应用提供更为稳定和安全的请求处理方案。

你可能感兴趣的:(java,spring,servlet,java,spring,springboot)