拦截器

在基于 Netty-Boot 的应用中,拦截器是非常重要的功能,它可以在请求到达业务处理器之前或请求完成后进行预处理或后处理。通过使用拦截器,开发者可以实现全局过滤、认证、日志记录等功能。本文将介绍如何在 Netty-Boot 中配置和使用拦截器。

拦截器原理

拦截器的作用是对请求进行预处理或后处理,类似于过滤器的功能。拦截器通常有以下几个步骤:

  1. 预处理 (before):在请求处理前执行拦截器逻辑,比如验证请求是否有权限访问资源,或者为日志记录开始计时。
  2. 请求处理:如果预处理通过,则将请求交给后续的业务处理器执行。
  3. 后处理 (after):在请求处理完成后执行拦截器逻辑,比如记录响应结果、计算请求处理耗时、释放资源等。

Netty-Boot 中的拦截器通过 HttpInterceptorModelHttpInteceptorConfigure 来配置。开发者可以根据 URL 模式进行拦截,定义哪些请求需要经过拦截器,哪些请求可以直接通过。

拦截器配置示例

1. 定义拦截器

首先,我们需要定义一个自定义的拦截器 GlobalInteceptor,它实现了 HttpInterceptor 接口,包含 beforeafter 两个核心方法。

import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class GlobalInteceptor implements HttpInterceptor {

  @Override
  public boolean before(ChannelHandlerContext ctx, FullHttpRequest request) {
    // 请求前处理逻辑
    log.info("请求拦截器 - 处理前: {}", request.uri());
    return true;  // 返回 true 表示继续处理请求;false 则终止请求
  }

  @Override
  public void after(ChannelHandlerContext ctx, FullHttpRequest request, FullHttpResponse response) {
    // 请求后处理逻辑
    log.info("请求拦截器 - 处理后: {}, 响应状态码: {}", request.uri(), response.status());
  }
}

在这个示例中,before 方法用于处理请求到达业务处理器之前的逻辑,after 方法则在请求完成后进行后处理,比如日志记录。

2. 配置拦截器

接下来,我们通过 HttpInterceptorModelHttpInteceptorConfigure 配置拦截器,定义需要拦截的 URL 模式。

package com.litongjava.netty.im.config;

import com.litongjava.annotation.AConfiguration;
import com.litongjava.annotation.AInitialization;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.netty.boot.http.HttpRequestRouter;
import com.litongjava.netty.boot.inteceptor.HttpInterceptorModel;
import com.litongjava.netty.boot.inteceptor.HttpInteceptorConfigure;
import com.litongjava.netty.boot.listener.ChannelConnectionListener;
import com.litongjava.netty.boot.server.NettyBootServer;
import com.litongjava.netty.boot.websocket.WebsocketRouter;
import com.litongjava.netty.im.handler.ChatHandler;
import com.litongjava.netty.im.handler.OkHandler;
import com.litongjava.netty.im.handler.TestHandler;
import com.litongjava.netty.im.handler.UploadHandler;
import com.litongjava.netty.im.handler.WsHandler;
import com.litongjava.netty.im.inteceptor.GlobalInteceptor;
import com.litongjava.netty.im.listener.MyChannelConnectionListener;

import lombok.extern.slf4j.Slf4j;

@AConfiguration
@Slf4j
public class WebConfig {

  @Initialization
  public void config() {
    NettyBootServer nettyBootServer = NettyBootServer.me();
    ChannelConnectionListener myChannelConnectionListener = new MyChannelConnectionListener();
    nettyBootServer.setChannelConnectionListener(myChannelConnectionListener);

    // 创建拦截器模型
    HttpInterceptorModel model = new HttpInterceptorModel();
    model.setName("GlobalInteceptor");  // 拦截器名称
    model.addBlockeUrl("/**"); // 拦截所有 URL
    model.addAllowedUrl("/admin/login"); // 允许访问 /admin/login,不拦截
    model.setInterceptor(new GlobalInteceptor()); // 设置拦截器实例

    // 配置拦截器
    HttpInteceptorConfigure configure = new HttpInteceptorConfigure();

    configure.add(model);
    // 设置拦截器到服务器
    nettyBootServer.setServerInteceptorConfigure(configure);
  }
}
  • addBlockeUrl("/**") 表示拦截所有的请求。
  • addAllowedUrl("/admin/login") 表示 /admin/login URL 允许访问,不经过拦截器。
  • setInterceptor(new GlobalInteceptor()) 设置自定义的拦截器。

3. 日志示例

配置完成后,所有的请求都会经过拦截器。以下是一次文件上传请求的日志记录:

2024-10-02 11:46:16.613 [nioEventLoopGroup-5-1] INFO  c.l.n.i.l.MyChannelConnectionListener.handlerAdded:13 - ctx:ChannelHandlerContext(DefaultNettyHandlerAdapter#0, [id: 0xfbfe1403, L:/127.0.0.1:80 - R:/127.0.0.1:5991])
2024-10-02 11:46:16.717 [nioEventLoopGroup-5-1] INFO  c.l.n.b.a.DefaultNettyHandlerAdapter.handleHttpRequest:60 - access:POST /upload HTTP/1.1
2024-10-02 11:46:16.721 [nioEventLoopGroup-5-1] INFO  c.l.n.i.i.GlobalInteceptor.before:13 - 请求拦截器 - 处理前: /upload
2024-10-02 11:46:16.858 [nioEventLoopGroup-5-1] INFO  c.l.n.i.h.UploadHandler.upload:53 - 文件上传成功: F:\files\Textbook-Thomas H. Cormen.pdf
2024-10-02 11:46:16.867 [nioEventLoopGroup-5-1] INFO  c.l.n.i.i.GlobalInteceptor.after:19 - 请求拦截器 - 处理后: /upload, 响应状态码: 200, 耗时: 149ms
2024-10-02 11:46:16.883 [nioEventLoopGroup-5-1] INFO  c.l.n.i.l.MyChannelConnectionListener.handlerRemoved:18 - ctx:ChannelHandlerContext(DefaultNettyHandlerAdapter#0, [id: 0xfbfe1403, L:/127.0.0.1:80 ! R:/127.0.0.1:5991])

日志展示了请求从建立连接到文件上传成功的全过程,同时拦截器记录了请求处理前后的信息。

4. 拦截器处理流程

  • 连接建立:日志记录了 ChannelConnectionListener 中的 handlerAdded 事件,表示客户端与服务器建立了连接。
  • 拦截器前置处理:在请求到达业务处理器之前,GlobalInteceptor.before 方法会被调用,并记录请求的 URI。
  • 文件上传处理:文件上传的业务逻辑处理在 UploadHandler.upload 方法中完成,处理成功后记录了上传文件的路径。
  • 拦截器后置处理:请求处理完成后,GlobalInteceptor.after 方法会被调用,记录响应状态码和处理耗时。
  • 连接断开:在客户端请求完成后,ChannelConnectionListener.handlerRemoved 方法会记录连接的断开。

总结

通过在 Netty-Boot 中配置拦截器,开发者可以轻松实现全局的请求过滤、权限验证、日志记录等功能。本文展示了如何定义自定义的拦截器,并将其配置到服务器中。拦截器的 beforeafter 方法可以灵活地处理请求的预处理和后处理,为开发者提供了强大的扩展能力。

拦截器的使用不仅简化了业务逻辑的处理,还为整个应用提供了更好的可维护性和安全性。