You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在LoopBack 4中正确集成Apitally中间件,使其对所有API请求生效而非仅Swagger相关路由

如何在LoopBack 4中正确集成Apitally中间件,使其对所有API请求生效而非仅Swagger相关路由

我明白你现在的困扰——Apitally中间件只在Swagger相关路由(比如/openapi.json)触发,普通API端点完全没反应,而且你不想挨个修改控制器。结合你提供的代码,我给你整理了几个关键调整,能让中间件对所有 incoming 请求都生效:


1. 微调Apitally中间件的适配逻辑

你的中间件已经把Express风格的Apitally路由适配成了LoopBack格式,这里只需要确保它能正确衔接LoopBack的中间件流程,以下是优化后的完整代码:

import { MiddlewareContext, Next } from '@loopback/rest';
import express from 'express';
import { useApitally } from 'apitally';

// 初始化Apitally的Express路由实例
const apitallyRouter = express();
apitallyRouter.use((req, res, next) => {
  console.log('[apitally] incoming', req.method, req.path);
  next();
});

// 配置Apitally核心参数
useApitally(apitallyRouter, {
  clientId: "CLIENT_ID",
  env: "prod",
  logger: {
    debug: console.debug,
    info: console.info,
    warn: console.warn,
    error: console.error,
  },
  requestLoggingConfig: {
    enabled: true,
    logQueryParams: true,
    logRequestHeaders: true,
    // logRequestBody: true,
    logResponseHeaders: true,
    // logResponseBody: true,
  },
});

// 适配为LoopBack兼容的中间件
export const apitallyMiddleware = (ctx: MiddlewareContext, next: Next) => {
  return new Promise<void>((resolve, reject) => {
    apitallyRouter(ctx.request, ctx.response, (err) => {
      if (err) return reject(err);
      resolve();
    });
  }).then(() => next());
};

2. 将Apitally中间件注册为全局中间件

现在需要把这个中间件注册到LoopBack应用中,让它对所有请求生效。在你的application.ts里添加注册逻辑:

import { apitallyMiddleware } from './path-to-your-middleware-file'; // 替换为实际文件路径

export class YourApplication extends BootMixin(ServiceMixin(RepositoryMixin(RestApplication))) {
  constructor(options: ApplicationConfig = {}) {
    super(options);

    // 注册Apitally为全局中间件(所有请求都会优先经过它)
    this.middleware(apitallyMiddleware);

    // ...其他应用配置(比如绑定控制器、数据源等)
  }
}

3. 调整自定义Sequence的执行顺序

你使用了自定义MySequence,之前的问题出在中间件执行顺序不对——你在findRoute之后才手动调用中间件,导致未匹配到路由的请求根本没机会触发Apitally。现在修改MySequence,让全局中间件在路由查找前自动执行:

import { inject } from '@loopback/core';
import {
  FindRoute,
  InvokeMethod,
  ParseParams,
  Reject,
  RequestContext,
  Send,
  SequenceActions,
  SequenceHandler,
  InvokeMiddleware,
} from '@loopback/rest';
import { AuthenticationBindings, AuthenticateFn } from '@loopback/authentication';
import { WinstonLogger } from 'winston';
import { LoggingBindings } from './keys';
import { RedisCacheService } from './services';
import { AnalyticsRepository } from './repositories';

export class MySequence implements SequenceHandler {
  @inject(SequenceActions.INVOKE_MIDDLEWARE, { optional: true })
  protected invokeMiddleware: InvokeMiddleware = () => Promise.resolve(false);

  constructor(
    @inject(SequenceActions.FIND_ROUTE) protected findRoute: FindRoute,
    @inject(SequenceActions.PARSE_PARAMS) protected parseParams: ParseParams,
    @inject(SequenceActions.INVOKE_METHOD) protected invoke: InvokeMethod,
    @inject(SequenceActions.SEND) public send: Send,
    @inject(SequenceActions.REJECT) public reject: Reject,
    @inject(AuthenticationBindings.AUTH_ACTION) protected authenticateRequest: AuthenticateFn,
    @inject(LoggingBindings.WINSTON_LOGGER) private logger: WinstonLogger,
    @service() private redisCacheService: RedisCacheService,
    @repository(AnalyticsRepository) private analyticsRepository: AnalyticsRepository,
  ) {}

  async handle(context: RequestContext) {
    const { request, response } = context;
    try {
      // 第一步:优先执行所有全局中间件(包括Apitally)
      const finished = await this.invokeMiddleware(context);
      if (finished) return; // 如果中间件已经处理了响应(比如返回404),直接结束流程

      // 第二步:执行路由查找、参数解析等核心逻辑
      const route = this.findRoute(request);
      // 移除之前手动调用apitallyMiddleware1的代码,全局注册后无需重复调用

      // await this.authenticateRequest(request);
      const args = await this.parseParams(request, route);
      const result = await this.invoke(route, args);
      this.send(response, result);
    } catch (err: any) {
      this.reject(context, err);
    }
  }
}

为什么之前的代码只在Swagger路由生效?

之前你在findRoute之后手动调用Apitally中间件,而LoopBack的findRoute会对不存在的路由直接抛出错误,导致中间件根本没机会执行。而Swagger相关路由是LoopBack内置的,findRoute能成功匹配,所以中间件会触发。

把中间件注册为全局并在Sequence最开始执行,就能确保**所有请求(包括不存在的路由、静态文件请求等)**都会经过Apitally中间件。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 10:43:10