中间件指南
本指南将引导您完成在 Finch 应用程序中创建和使用中间件的步骤。中间件提供了一种便捷的机制,用于检查和过滤进入应用程序的 HTTP 请求。
什么是中间件?
Finch 中的中间件是位于传入的 HTTP 请求和路由处理程序(控制器或 index 函数)之间的类。它允许您在请求到达控制器之前运行逻辑 — 例如,检查请求头、记录请求日志、验证令牌、修改请求参数或阻止未授权访问。
每个中间件类必须继承抽象类 Middleware 并实现 handle() 方法。
中间件的工作原理
当请求匹配到附加了中间件的路由时,Finch 会在将请求传递给控制器或 index 函数之前按顺序执行中间件管道。流程如下:
- 路由模式匹配
- HTTP 方法、主机和端口验证
- 身份验证检查(
auth) - 中间件执行(按顺序运行每个中间件的
handle()方法) - 权限检查
- 控制器/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. 使用构造函数
将中间件实例列表传递给 FinchRoute 的 middlewares 参数:
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 |