中间件指南

本指南将引导您完成在 Finch 应用程序中创建和使用中间件的步骤。中间件提供了一种便捷的机制,用于检查和过滤进入应用程序的 HTTP 请求。

什么是中间件?

Finch 中的中间件是位于传入的 HTTP 请求和路由处理程序(控制器或 index 函数)之间的类。它允许您在请求到达控制器之前运行逻辑 — 例如,检查请求头、记录请求日志、验证令牌、修改请求参数或阻止未授权访问。

每个中间件类必须继承抽象类 Middleware 并实现 handle() 方法。

中间件的工作原理

当请求匹配到附加了中间件的路由时,Finch 会在将请求传递给控制器或 index 函数之前按顺序执行中间件管道。流程如下:

  1. 路由模式匹配
  2. HTTP 方法、主机和端口验证
  3. 身份验证检查(auth
  4. 中间件执行(按顺序运行每个中间件的 handle() 方法)
  5. 权限检查
  6. 控制器/index 执行

返回值

handle() 方法返回 Future<String?>

  • 返回 null — 请求通过,继续传递到下一个中间件或路由处理程序。
  • 返回非空 String — 请求被阻止。中间件管道停止,路由不会被匹配。

如果多个中间件附加到一个路由,它们将按顺序执行。如果任何中间件返回非空字符串,则跳过剩余的中间件,请求被拒绝。

创建中间件

要创建中间件,请继承 Middleware 类并重写 handle() 方法:

import 'package:finch/finch_route.dart';

class MyMiddleware extends Middleware {
  @override
  Future<String?> handle() async {
    // 您的逻辑
    return null; // 允许请求继续
  }
}

访问请求

在中间件内部,您可以使用 rq(由 Middleware 基类提供)访问当前请求:

class LogMiddleware extends Middleware {
  @override
  Future<String?> handle() async {
    print('请求: ${rq.method} ${rq.uri.path}');
    return null;
  }
}

添加参数

您可以使用 rq.addParam() 从中间件向请求中注入数据。这些数据将在下游的控制器和模板中可用:

class TestMiddleware extends Middleware {
  @override
  Future<String?> handle() async {
    rq.addParam('middleware', 'Test Middleware Active');
    return null;
  }
}

阻止请求

返回非空字符串以阻止请求到达路由处理程序:

class ApiKeyMiddleware extends Middleware {
  @override
  Future<String?> handle() async {
    final apiKey = rq.header('X-API-Key');
    if (apiKey != 'my-secret-key') {
      rq.renderError(401, message: 'API 密钥无效');
      return 'Unauthorized'; // 阻止请求
    }
    return null; // 允许请求继续
  }
}

将中间件附加到路由

有两种方法可以将中间件附加到路由。

1. 使用构造函数

将中间件实例列表传递给 FinchRoutemiddlewares 参数:

final testMiddleware = TestMiddleware();
final logMiddleware = LogMiddleware();

FinchRoute(
  path: '/info',
  index: homeController.info,
  middlewares: [testMiddleware, logMiddleware],
);

2. 使用链式 API(Fluent API)

使用 .middleware() 方法将中间件链接到路由:

FinchRoute(
  path: '/info',
  index: homeController.info,
).middleware(TestMiddleware()).middleware(LogMiddleware());

父路由上的中间件

当中间件附加到具有 children 的父路由时,中间件将在处理任何子路由之前运行。这允许您将共享逻辑(如身份验证或日志记录)应用于一组路由:

FinchRoute(
  path: '/admin',
  middlewares: [AdminMiddleware()],
  children: [
    FinchRoute(
      path: '/dashboard',
      index: adminController.dashboard,
    ),
    FinchRoute(
      path: '/users',
      index: adminController.users,
    ),
  ],
);

在此示例中,AdminMiddleware 将在任何对 /admin/dashboard/admin/users 的请求之前执行。

实用示例

速率限制中间件

class RateLimitMiddleware extends Middleware {
  static final Map<String, List<DateTime>> _requests = {};
  final int maxRequests;
  final Duration window;

  RateLimitMiddleware({
    this.maxRequests = 100,
    this.window = const Duration(minutes: 1),
  });

  @override
  Future<String?> handle() async {
    final ip = rq.clientIP;
    final now = DateTime.now();
    _requests[ip] = (_requests[ip] ?? [])
      ..removeWhere((t) => now.difference(t) > window)
      ..add(now);

    if (_requests[ip]!.length > maxRequests) {
      rq.renderError(429, message: '请求过多');
      return 'Rate limit exceeded';
    }
    return null;
  }
}

CORS 中间件

class CorsMiddleware extends Middleware {
  final String allowedOrigin;

  CorsMiddleware({this.allowedOrigin = '*'});

  @override
  Future<String?> handle() async {
    rq.response.headers.add('Access-Control-Allow-Origin', allowedOrigin);
    rq.response.headers.add('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    rq.response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    return null;
  }
}

维护模式中间件

class MaintenanceMiddleware extends Middleware {
  final bool isEnabled;

  MaintenanceMiddleware({this.isEnabled = false});

  @override
  Future<String?> handle() async {
    if (isEnabled) {
      rq.renderError(503, message: '服务正在维护中');
      return 'Maintenance mode';
    }
    return null;
  }
}

中间件与身份验证控制器的比较

特性 中间件 身份验证控制器
用途 通用请求过滤 身份验证和授权
执行顺序 auth 之后,权限之前 中间件之前
返回类型 Future<String?> Future<bool>
可修改请求 是(rq.addParam
可渲染错误
每路由数量 多个(列表) 一个
子路由继承

当您需要完整的身份验证和会话管理时,使用身份验证控制器。其他所有场景使用中间件 — 日志记录、请求头验证、速率限制、CORS、功能开关等。

完整示例

以下是在 Finch 应用程序中使用中间件的完整示例:

1. 创建中间件类:

// lib/middleware/test_middleware.dart
import 'package:finch/finch_route.dart';

class TestMiddleware extends Middleware {
  @override
  Future<String?> handle() async {
    rq.addParam('middleware', 'Test Middleware Active');
    return null;
  }
}

2. 在路由中注册中间件:

// lib/route/web_route.dart
import '../middleware/test_middleware.dart';

final testMiddleware = TestMiddleware();

List<FinchRoute> routes = [
  FinchRoute(
    key: 'root.info',
    path: 'info',
    extraPath: ['api/info'],
    index: homeController.info,
    middlewares: [testMiddleware],
  ),
];

3. 在控制器中访问中间件数据:

class HomeController extends Controller {
  Future<String> info() async {
    final middlewareParam = rq.get('middleware');
    return rq.renderString(text: '中间件说: $middlewareParam');
  }
}

API 参考

Middleware(抽象类)

成员 类型 描述
rq Request(getter) 访问当前的 HTTP 请求对象
handle() Future<String?> 重写以实现中间件逻辑。返回 null 表示通过,返回非空字符串表示阻止。

FinchRoute 中间件成员

成员 类型 描述
middlewares List<Middleware> 附加到路由的中间件实例列表
middleware(m) FinchRoute 链式方法,用于添加中间件;返回路由以支持链式调用
handleMiddlewares() Future<bool> 按顺序执行所有中间件;如果全部通过则返回 true