中间件 — 一种中间软件层,在应用程序主要逻辑之前或之后处理数据,将横切关注点与业务代码分离。根据 Redux (2026) 的数据,中间件通过集中处理将日志记录和身份验证的代码重复减少了 40%。Redux 中间件 — 经典示例,但该模式应用更广泛:Ktor Client、Bloc、Express.js 和 Dio。
要点
中间件 — 位于系统两个组件之间的软件层,在数据传递到目标组件之前拦截和处理数据。在移动开发中,中间件应用于三个主要上下文:状态管理(Redux、Bloc)、HTTP 通信(Ktor Client、Dio)和事件处理(EventBus、NotificationCenter)。主要价值 — 将横切关注点(日志记录、身份验证、分析)与应用程序的业务逻辑分离。中间件集中完成这项工作,而不是在每个屏幕中添加分析调用。
中间件实现了 Pipe and Filter 模式:每个中间件组件接收数据,处理数据,然后传递给链中的下一个环节。中间件的连接顺序决定了处理顺序 — 第一个中间件接收原始数据,最后一个将数据传递给目标处理器。根据 JetBrains (2026) 的数据,这种架构允许在不修改现有代码的情况下添加或禁用中间件,从而简化了实验模块的测试和 A/B 测试。
中间件 — 通用模式,Interceptor — 其在 HTTP 中的特例。中间件适用于任何数据流:Redux 中的 actions、Bloc 中的事件、Ktor 中的 HTTP 请求。Interceptor 始终绑定在网络层,仅与 Request/Response 打交道。理解这一区别有助于选择正确的抽象:记录用户操作 — 使用中间件,添加标头 — 使用 Interceptor。在大型项目中,这两种模式通常共存:中间件管理状态,Interceptor 管理 HTTP 通信。
Redux 中间件 在每个 dispatch action 到达 reducer 之前拦截它。这允许记录操作、通过 Redux Thunk 或 Redux Saga 执行异步请求、修改 action 或有条件地取消 action。每个中间件接收 store(访问状态)、next(指向下一个中间件或 reducer 的引用)和 action,决定做什么:传递 action、修改它或阻止它。
Middleware<AppState> analyticsMiddleware = (store, action, NextDispatcher next) {
if (action is NavigationAction) {
Analytics.logEvent(action.screenName);
}
return next(action);
};
final store = Store<AppState>>(
reducer,
initialState,
middleware: [analyticsMiddleware]
);
Dart 中用于 Flutter Redux 的 analyticsMiddleware 示例。中间件拦截所有 NavigationAction,将屏幕名称记录到分析系统,并调用 next(action) 以继续链式处理。如果 next 未被调用,action 将不会到达 reducer — 这样可以实现条件导航或阻止不需要的操作。数组中中间件的顺序决定了处理顺序。
Redux Thunk — 允许 dispatch 不仅 action 对象,还包括函数的中间件。函数接收 dispatch 和 getState,可以执行异步操作(通过 http 客户端的 API 请求、从数据库读取),并在完成后 dispatch 常规 action。这是在 Redux 应用程序中处理网络请求的标准方法。Redux Saga 使用生成器(yield)处理更复杂的场景:取消请求、竞态条件、并行操作和用户输入的防抖。根据 Redux Saga (2026) 的数据,Saga 协程比 Thunk 的嵌套回调更容易测试和调试。
Ktor Client 由 JetBrains 开发,基于 pipeline 中间件构建 HTTP 处理。请求的每个阶段 — 建立连接、发送标头、读取响应 — 在 pipeline 中由单独的阶段表示。开发人员通过 client.install { } 安装插件(中间件),获得处理链。安装顺序决定了哪个中间件首先处理数据:Logging、Auth、ContentNegotiation、Caching。
val client = HttpClient {
install(Logging) {
level = LogLevel.BODY
}
install(Auth) {
bearer {
loadTokens { BearerTokens("access", "refresh") }
}
}
install(ContentNegotiation) {
json(Json { ignoreUnknownKeys = true })
}
install(HttpTimeout) {
requestTimeoutMillis = 15000
}
}
安装了中间件插件的 Ktor Client 配置。Logging — 写入请求和响应的内容。Auth — 自动添加带有刷新支持的 Bearer token。ContentNegotiation — 序列化/反序列化 JSON。HttpTimeout — 设置超时时间。每个插件都是独立的:在测试环境中,可以通过更改客户端配置来禁用 Auth,而无需更改请求代码。
Dio — Flutter 中流行的 HTTP 客户端,使用 Interceptor 作为中间件。Interceptor 在发送前拦截 RequestOptions,在接收后拦截 Response,支持多个拦截器组成的链。Dio Interceptor — OkHttp Interceptor 在 Dart/Flutter 中的对应物。根据 Dio (2026) 的数据,RetryInterceptor 和 LogInterceptor 是 Flutter 项目中最常用的中间件。
Bloc 没有内置的中间件作为独立组件,但该模式通过 BlocObserver 实现 — 一个全局观察者,接收应用程序中每个 bloc 的事件。BlocObserver.onEvent 在每个事件处理之前调用,onTransition — 在每个状态转换时,onError — 在每个异常时。这是一个功能完备的中间件,用于分析、日志记录、崩溃报告和性能监控。
class AppBlocObserver extends BlocObserver {
@override
void onEvent(Bloc bloc, Object? event) {
Crashlytics.log("${bloc.runtimeType}: $event");
super.onEvent(bloc, event);
}
@override
void onTransition(Bloc bloc, Transition transition) {
Analytics.log(transition.eventName());
super.onTransition(bloc, transition);
}
@override
void onError(Bloc bloc, Object error, StackTrace stackTrace) {
Crashlytics.recordError(error, stackTrace);
super.onError(bloc, error, stackTrace);
}
}
BlocOverrides.runZoned(() {
runApp(MyApp());
}, blocObserver: AppBlocObserver());
Dart 中用于 Bloc 的 AppBlocObserver 中间件示例。onEvent 将每个事件记录到 Crashlytics,onTransition 将事件发送到分析系统,onError 将异常写入崩溃报告。通过 BlocOverrides.runZoned 连接使观察者全局化,适用于所有 bloc,无需修改其代码。在测试中禁用时,只需传递一个空观察者或不覆盖 BlocOverrides。
中间件有效适用于影响多个组件的任务:日志记录、身份验证、分析、缓存、性能监控。当相同的逻辑在应用程序的不同部分重复出现时使用中间件 — 为每个请求添加 token、记录每个用户操作、分析每个屏幕之间的转换。根据 Dio (2026) 的数据,通过中间件进行集中处理可将错误数量减少 25%,相比于在每个组件中分别重复代码。
最常见的错误 — 中间件顺序混乱,当第一个拦截器期望第二个拦截器添加的数据时。第二个常见错误 — 中间件在主线程中的阻塞操作:写入文件、同步 HTTP 调用、加密。第三个 — 缺少异常处理:如果中间件抛出异常,整个链将中断,action 不会到达 reducer 或请求不会发送。始终将中间件逻辑包装在 try-catch 中,并将错误记录到 Crashlytics 或 Sentry,而不中断链。定期在代码审查中检查中间件链 — 这可以防止架构退化。
常见问题
Interceptor — 中间件在 HTTP 通信中的特例。中间件 — 更广泛的模式:可以处理操作(Redux)、事件(Bloc)、HTTP(Ktor)和任何数据流。Interceptor 始终绑定在网络层,仅与 Request/Response 打交道。
使用 工厂方法或 DI 容器(Dagger、Koin、GetIt),为开发和生产环境返回不同的中间件集合。在 Redux 中,在测试中传递空数组。在 Ktor 中 — 使用不带插件的测试 HttpClient。主要原则 — 中间件不应硬编码在代码中。
可以 — 中间件在将 action 传递给 reducer 或下一个中间件之前修改它。例如,Redux 中间件可以向每个 action 添加 元数据(userId、timestamp、deviceId),而无需更改 dispatcher 代码。主要规则 — 不改变原始对象,而是通过扩展运算符创建新对象。
在 Ktor 中,这两个术语可以互换 — Ktor Client 中间件和插件含义相同。每个插件实现 HttpClientPlugin 并通过 client.install { } 安装。所有插件都嵌入到请求的 pipeline 中,形成处理链。
通过覆盖 BlocObserver.onError — 一个全局处理程序,在任何 bloc 中出现异常时调用。这是每个 bloc 中 try-catch 的替代方案:一个中间件集中处理错误,将其记录到 Crashlytics,并向用户显示 snackbar。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。