三种拦截Rest API的方法-过滤器、拦截器、切片

过滤器方式实现拦截(Filter)

通过继承Servlet的Filter类来实现拦截:

@Component
public class TimeFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("time filter init");
    }
    /**
     * 处理服务的请求时间
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //System.out.println("time filter start");
        long start = System.currentTimeMillis();
        chain.doFilter(request,response);
        //System.out.println("time filter 耗时:" + (System.currentTimeMillis() - start));
        //System.out.println("time filter finish");

    }
    @Override
    public void destroy() {
        //System.out.println("time filter destroy");
    }
}

假如这个Filter是第三方jar提供的,怎么加入我们自己的工程呢?通过org.springframework.boot.web.servlet.FilterRegistrationBean来加入

@Configuration
public class WebConfig {
    
    @Bean
    public FilterRegistrationBean timeFilter() {
        
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        
        TimeFilter timeFilter = new TimeFilter();
        registrationBean.setFilter(timeFilter);
        
        List<String> urls = new ArrayList<>();
        urls.add("/*");
        registrationBean.setUrlPatterns(urls);
        
        return registrationBean;
        
    }

}

拦截器方式实现拦截(Interceptor)

此种方式可以获取到拦截的类名称、方法名称,不能获取到方法参数,原因是在dispatcherservlet源码中,经过preHandle才对方法参数通过request里面开始处理拼接)

1.继承HandlerInterceptor,preHandle在控制器方法调用之前执行,postHandle在控制器方法正常执行后执行,afterCompletion不管控制器方法执行成功与否,都会执行;拦截器优于过滤器的地方就是拦截器有handler这个参数可以了解到针对哪个具体的方法进行了拦截。
复制代码

@Component
public class TimeInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        //打印类名
        System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
        //打印方法名
        System.out.println(((HandlerMethod)handler).getMethod().getName());
        request.setAttribute("startTime",System.currentTimeMillis());
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
        Long start = (Long)request.getAttribute("startTime");
        System.out.println("time intercept 耗时:" + (System.currentTimeMillis() - start));
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception ex) throws Exception {
        System.out.println("afterCompletion");
        Long start = (Long)request.getAttribute("startTime");
        System.out.println("time intercept 耗时:" + (System.currentTimeMillis() - start));
        System.out.println("ex is" + ex);
    }
}

2. 配置拦截器注入到spring容器(配置类需要继承WebMvcConfigurerAdapter,重写addInterceptors,手动添加自定义拦截器来到达注入的目的),也可为异步请求加入拦截器

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Autowired
    private TimeInterceptor timeInterceptor;

    /**
     * 针对异步的拦截器配置,拦截异步请求
     * @param configurer
     */
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        super.configureAsyncSupport(configurer);
        //比如如下给异步服务请求添加拦截器
        //configurer.registerCallableInterceptors((CallableProcessingInterceptor) timeInterceptor);
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(timeInterceptor);
    }
}

切片方式实现拦截(Aspect)

可以拦截到类名、方法名,方法参数名
复制代码

@Aspect
@Component
public class TimeAspect {
    //切入点
    @Around("execution(* com.zlt.web.controller.UserController.*(..))")
    //增强
    public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {

            System.out.print("time aspect start");
            Object[] args = pjp.getArgs();
            for (Object arg :args){
            System.out.println("arg is" + arg);
            }
            long start = System.currentTimeMillis();
            //调用被拦截的方法
            Object object = pjp.proceed();
            System.out.println("time filter 耗时:" + (System.currentTimeMillis() - start));
            System.out.println("time aspect end");
            return object; 
    }
}

小结
区别:

过滤器:可以拿到原始的HTTP请求和响应信息,拿不到处理请求的方法值信息
拦截器:既可以拿到HTTP请求和响应信息,也可以拿到请求的方法信息,拿不到方法调用的参数值信息
切片:可以拿到请求方法的传入参数值,拿不到原始的HTTP请求和响应的对象
发起一个请求,若三者共存的情况下:

正常运行顺序为:filter-interceptor-controllerAdvice-aspect-controller
异常情况下:controller-aspect-controllerAdvice-interceptor-filter

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在FastAPI中,可以使用拦截(middleware)和过滤器(dependency)来处理请求和响应。它们都可以在请求到达路由处理函数之前或之后执行一些操作,但它们的作用和使用方法不太一样。 拦截是在请求到达路由处理函数之前或之后执行的一系列操作,它们可以用于记录请求日志、身份验证、异常处理等操作。使用FastAPI拦截可以很方便地实现这些操作,例如: ```python from fastapi import FastAPI, Request app = FastAPI() @app.middleware("http") async def log_requests(request: Request, call_next): """ 记录请求日志的拦截 """ print(f"Received request: {request.method} {request.url}") response = await call_next(request) print(f"Sent response: {response.status_code}") return response ``` 在这个例子中,我们定义了一个记录请求日志的拦截,它会在每次请求到达路由处理函数之前打印请求信息,并在响应返回后打印响应信息。这个拦截使用了FastAPI的`middleware`装饰,它指定了拦截的类型为`http`,表示它要处理HTTP请求。 过滤器是在请求到达路由处理函数之前执行的一系列操作,它们可以用于身份验证、请求参数校验等操作。使用FastAPI过滤器可以很方便地实现这些操作,例如: ```python from fastapi import FastAPI, Depends app = FastAPI() async def check_token(token: str): """ 检查token的依赖性 """ if token != "secret_token": raise HTTPException(status_code=401, detail="Invalid token") @app.get("/") async def read_root(token: str = Depends(check_token)): """ 需要token验证的路由处理函数 """ return {"Hello": "World"} ``` 在这个例子中,我们定义了一个需要token验证的路由处理函数,并使用了`Depends`装饰来指定依赖性。这个依赖性函数`check_token`会在请求到达路由处理函数之前执行,它会检查请求中的token参数是否正确。如果token不正确,则会抛出一个HTTP异常,返回401错误码。 希望这些信息能够帮助您了解FastAPI中的拦截过滤器

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值