移动应用中间件 — 基础、架构与应用

作者: IT Sectr 发布日期: 2026-03-09 阅读时间: 8 分钟

中间件 — 一种中间软件层,在应用程序主要逻辑之前或之后处理数据,将横切关注点与业务代码分离。根据 Redux (2026) 的数据,中间件通过集中处理将日志记录和身份验证的代码重复减少了 40%。Redux 中间件 — 经典示例,但该模式应用更广泛:Ktor Client、Bloc、Express.js 和 Dio。

要点

  • 中间件 — 数据源与业务逻辑之间的层,隔离横切关注点。
  • Redux 中间件 拦截 dispatch 并在 reducer 之前或之后修改 action。
  • Bloc 通过 BlocObserver 使用中间件进行日志记录和分析。
  • Ktor Client 基于带有 Logging 和 Auth 插件的 pipeline 构建 HTTP 中间件。
  • Dio Interceptor — Flutter 中用于 HTTP 请求的中间件,带有拦截器链。

什么是中间件?

中间件 — 位于系统两个组件之间的软件层,在数据传递到目标组件之前拦截和处理数据。在移动开发中,中间件应用于三个主要上下文:状态管理(Redux、Bloc)、HTTP 通信(Ktor Client、Dio)和事件处理(EventBus、NotificationCenter)。主要价值 — 将横切关注点(日志记录、身份验证、分析)与应用程序的业务逻辑分离。中间件集中完成这项工作,而不是在每个屏幕中添加分析调用。

Pipe and Filter 架构

中间件实现了 Pipe and Filter 模式:每个中间件组件接收数据,处理数据,然后传递给链中的下一个环节。中间件的连接顺序决定了处理顺序 — 第一个中间件接收原始数据,最后一个将数据传递给目标处理器。根据 JetBrains (2026) 的数据,这种架构允许在不修改现有代码的情况下添加或禁用中间件,从而简化了实验模块的测试和 A/B 测试。

与 Interceptor 的区别

中间件 — 通用模式,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、修改它或阻止它。

dart
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 — 这样可以实现条件导航或阻止不需要的操作。数组中中间件的顺序决定了处理顺序。

异步中间件:Thunk 和 Saga

Redux Thunk — 允许 dispatch 不仅 action 对象,还包括函数的中间件。函数接收 dispatch 和 getState,可以执行异步操作(通过 http 客户端的 API 请求、从数据库读取),并在完成后 dispatch 常规 action。这是在 Redux 应用程序中处理网络请求的标准方法。Redux Saga 使用生成器(yield)处理更复杂的场景:取消请求、竞态条件、并行操作和用户输入的防抖。根据 Redux Saga (2026) 的数据,Saga 协程比 Thunk 的嵌套回调更容易测试和调试。

HTTP 客户端中的中间件

Ktor Client 由 JetBrains 开发,基于 pipeline 中间件构建 HTTP 处理。请求的每个阶段 — 建立连接、发送标头、读取响应 — 在 pipeline 中由单独的阶段表示。开发人员通过 client.install { } 安装插件(中间件),获得处理链。安装顺序决定了哪个中间件首先处理数据:Logging、Auth、ContentNegotiation、Caching。

kotlin
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,而无需更改请求代码。

Flutter 中的 Dio Interceptor

Dio — Flutter 中流行的 HTTP 客户端,使用 Interceptor 作为中间件。Interceptor 在发送前拦截 RequestOptions,在接收后拦截 Response,支持多个拦截器组成的链。Dio Interceptor — OkHttp Interceptor 在 Dart/Flutter 中的对应物。根据 Dio (2026) 的数据,RetryInterceptor 和 LogInterceptor 是 Flutter 项目中最常用的中间件。

Bloc 架构中的中间件

Bloc 没有内置的中间件作为独立组件,但该模式通过 BlocObserver 实现 — 一个全局观察者,接收应用程序中每个 bloc 的事件。BlocObserver.onEvent 在每个事件处理之前调用,onTransition — 在每个状态转换时,onError — 在每个异常时。这是一个功能完备的中间件,用于分析、日志记录、崩溃报告和性能监控。

dart
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%,相比于在每个组件中分别重复代码。

  • 不要滥用 — 过多的中间件会使调试变得困难,并因额外的调用而降低性能
  • 顺序很重要 — 第一个中间件接收原始形式的数据,最后一个 — 在所有修改之后
  • 异步操作 — 将繁重的调用转移到异步中间件,不要阻塞主 UI 线程
  • 可测试性 — 每个中间件应通过模拟环境进行隔离测试
  • 记录链 — 明确描述项目中连接了哪些中间件及其顺序

使用中间件的常见错误

最常见的错误 — 中间件顺序混乱,当第一个拦截器期望第二个拦截器添加的数据时。第二个常见错误 — 中间件在主线程中的阻塞操作:写入文件、同步 HTTP 调用、加密。第三个 — 缺少异常处理:如果中间件抛出异常,整个链将中断,action 不会到达 reducer 或请求不会发送。始终将中间件逻辑包装在 try-catch 中,并将错误记录到 Crashlytics 或 Sentry,而不中断链。定期在代码审查中检查中间件链 — 这可以防止架构退化。

常见问题

中间件与 Interceptor 有何区别?

Interceptor — 中间件在 HTTP 通信中的特例。中间件 — 更广泛的模式:可以处理操作(Redux)、事件(Bloc)、HTTP(Ktor)和任何数据流。Interceptor 始终绑定在网络层,仅与 Request/Response 打交道。

如何在测试环境中禁用中间件?

使用 工厂方法或 DI 容器(Dagger、Koin、GetIt),为开发和生产环境返回不同的中间件集合。在 Redux 中,在测试中传递空数组。在 Ktor 中 — 使用不带插件的测试 HttpClient。主要原则 — 中间件不应硬编码在代码中。

中间件能在 dispatch 后修改 action 吗?

可以 — 中间件在将 action 传递给 reducer 或下一个中间件之前修改它。例如,Redux 中间件可以向每个 action 添加 元数据(userId、timestamp、deviceId),而无需更改 dispatcher 代码。主要规则 — 不改变原始对象,而是通过扩展运算符创建新对象。

Ktor 中的中间件和 Interceptor 有什么区别?

在 Ktor 中,这两个术语可以互换 — Ktor Client 中间件插件含义相同。每个插件实现 HttpClientPlugin 并通过 client.install { } 安装。所有插件都嵌入到请求的 pipeline 中,形成处理链。

Bloc 中的中间件如何处理错误?

通过覆盖 BlocObserver.onError — 一个全局处理程序,在任何 bloc 中出现异常时调用。这是每个 bloc 中 try-catch 的替代方案:一个中间件集中处理错误,将其记录到 Crashlytics,并向用户显示 snackbar。

总结

  • 中间件 — 用于隔离应用程序组件之间横切关注点的通用模式,比 Interceptor 更广泛。
  • Redux 中间件 拦截 dispatch 以进行日志记录、异步请求(Thunk)和复杂场景(Saga)。
  • Ktor Client 通过 pipeline 实现中间件,带有独立的 Logging、Auth、ContentNegotiation 插件。
  • BlocObserver — Flutter Bloc 的中间件:onEvent、onTransition 和 onError 全局处理所有 bloc。
  • Dio Interceptor — Flutter 的 HTTP 中间件,链与 OkHttp Interceptor 类似。
  • 中间件的连接顺序 决定了数据处理顺序 — 明确记录它。
  • 正确使用中间件 可将代码重复减少 25-40%,并简化横切关注点的单元测试。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读