0

我想在我的 LoopBack4 应用程序中增强一个拦截器,它目前只是在命令行上打印控制器方法调用的开始和结束 - 如下所述:https ://loopback.io/doc/en/lb4/拦截器.html

我的日志拦截器看起来像这样:

export const Log: Interceptor = async (invocationCtx, next) => {
    // Wait until the interceptor/method chain returns
    const req = await invocationCtx.get(RestBindings.Http.REQUEST);

    try
    {
        const stackinfo = 'Class: ' + invocationCtx.targetClass.name + ' | Method: ' + invocationCtx.methodName + " | Request IPs: " + req.ips.concat(', ');

        logger.trace('Starting - ' + stackinfo);

        const result = await next();
        const res = await invocationCtx.get(RestBindings.Http.RESPONSE);

        logger.trace('Ending - ' + stackinfo + ' | Response Status Code: ' + res.statusCode);

        return result;
    }
    catch (e)
    {
        logger.error(e);
        throw e;
    }
};

现在我想增强这个拦截器,以便将一些统计数据记录到我的 MySQL 数据源中。我的问题是,如何访问拦截器内的存储库?我是否必须注入存储库,如果是,我该怎么做?还是有更好的方法来实现这一目标?

4

2 回答 2

0

我自己找到了解决方案:

  1. 创建服务:
export class StatisticService
{
    constructor(
        @repository(StatisticRecordRepository) public statisticsRepository: StatisticRecordRepository
    ) {}


    async increment(key: string, addend = 1): Promise<void>
    {
        const existing = await this.statisticsRepository.findOne({where: {StatsKey: key}});
        if(existing !== null)
        {
            // @ts-ignore
            existing.Counter = existing.Counter + addend;
            existing.UpdateTs = (new Date()).toISOString();
            await this.statisticsRepository.update(existing);
        }
        else
        {
            await this.statisticsRepository.create(new StatisticRecord({
                                                                           StatsKey: key,
                                                                           Counter:  addend
                                                                       }));
        }
    }
}


export const StatisticsServiceBindings = {
    VALUE: BindingKey.create<StatisticService>("services.StatisticsService")
};
  1. 在 Application 构造函数中绑定服务:
this.bind(StatisticsServiceBindings.VALUE).toClass(StatisticService);
  1. 在日志拦截器中获取和使用服务:
const stats = await invocationCtx.get(StatisticsServiceBindings.VALUE);
stats.increment(invocationCtx.targetClass.name + '::' + invocationCtx.methodName + ' [' + res.statusCode + ']');
于 2019-09-30T12:21:43.870 回答
0

您可以通过 invocationCtx.target 访问拦截器中的存储库,如下所示:

export const exampleInterceptor: Interceptor = async (invocationCtx, next) => {
  const exampleRepo = invocationCtx.target.exampleRepository;
  const anotherExampleRepo = invocationCtx.target.anotherExampleRepository;
};

假设您在拦截器所在的控制器中有相应的 @repository 装饰器(适用于类级别和方法级别的拦截器)

@intercept(exampleInterceptor)
export class ExampleController {
  constructor(
    @repository(ExampleRepository)
    public exampleRepository: ExampleRepository,
    @repository(AnotherExampleRepository)
    public anotherExampleRepository: AnotherExampleRepository
  ) {}
}

不确定这是否是推荐的解决方案。很想听听其他建议。

于 2020-04-25T20:19:50.070 回答