Nodejs 中间件依赖注入工具 middleware-injector 如何

Nodejs 中间件依赖注入工具 middleware-injector 如何

中间件模式算是最 Node 风格的 Web 应用构建方式,但是我在使用 express 的中间件的过程中,发现似乎缺少管理中间件之间的依赖的功能,找了一些库,但是感觉这个简单的问题被描述得复杂化了,于是我自己写了一个简单的依赖注入工具,总计才 12 行。

源码贴在这里:

_ = require 'underscore'
async = require 'async'

module.exports = (req, res, next) -> req.inject = (dependency, callback) -> if req.injected dependency = _.reject dependency, (item) -> return item in req.injected

async.eachSeries dependency, (item, callback) ->
  req.injected = [] unless req.injected
  req.injected.push item
  item req, res, callback
, callback

next()

也发在了 npm 上面: https://www.npmjs.org/package/middleware-injector 当然,这是花了半个小时搞出来的,肯定不是最好的解决方案,欢迎提供更好的解决方案。

下面是一个典型的应用场景:

parseToken = (req, res, next) ->
  req.token = req.cookies.token
  next()

accountInfo = (req, res, next) -> req.inject [parseToken], -> mAccount.authenticate req.token, (account) -> req.account = account next()

errorHandling = (req, res, next) -> res.error = (name, param) -> param = _.extend param, error: name res.json 400, param next()

requestAuthenticate = (req, res, next) -> req.inject [accountInfo, errorHandling], -> if req.account next() else if req.method == ‘GET’ res.redirect ‘/account/login/’ else res.error ‘auth_failed’


11 回复

Node.js 中间件依赖注入工具 middleware-injector 如何使用

中间件模式是 Node.js 构建 Web 应用程序的一种常见方法。然而,在使用 Express 等框架时,我发现中间件之间缺乏一种有效的依赖管理机制。为了解决这个问题,我编写了一个简单的依赖注入工具 middleware-injector,总共只有 12 行代码。

源码

const _ = require('lodash');
const async = require('async');

module.exports = (req, res, next) => {
  req.inject = (dependency, callback) => {
    if (req.injected) {
      dependency = _.reject(dependency, (item) => {
        return req.injected.includes(item);
      });
    }

    async.eachSeries(dependency, (item, callback) => {
      if (!req.injected) {
        req.injected = [];
      }
      req.injected.push(item);
      item(req, res, callback);
    }, callback);
  };

  next();
};

该工具已经发布到了 npm 上:middleware-injector

示例应用场景

假设我们有一个应用需要解析 token、获取账户信息,并进行错误处理。我们可以使用 middleware-injector 来管理这些中间件之间的依赖关系。

// 解析 token
const parseToken = (req, res, next) => {
  req.token = req.cookies.token;
  next();
};

// 获取账户信息
const accountInfo = (req, res, next) => {
  req.inject([parseToken], () => {
    mAccount.authenticate(req.token, (account) => {
      req.account = account;
      next();
    });
  });
};

// 错误处理
const errorHandling = (req, res, next) => {
  res.error = (name, param) => {
    param = _.extend(param, { error: name });
    res.status(400).json(param);
  };
  next();
};

// 请求认证
const requestAuthenticate = (req, res, next) => {
  req.inject([accountInfo, errorHandling], () => {
    if (req.account) {
      next();
    } else {
      if (req.method === 'GET') {
        res.redirect('/account/login/');
      } else {
        res.error('auth_failed', {});
      }
    }
  });
};

使用说明

  1. 安装

    npm install middleware-injector
    
  2. 引入

    const middlewareInjector = require('middleware-injector');
    
  3. 使用: 在你的 Express 应用中,将 middlewareInjector 作为中间件使用。

    app.use(middlewareInjector);
    
    // 使用中间件
    app.use(parseToken);
    app.use(accountInfo);
    app.use(errorHandling);
    app.use(requestAuthenticate);
    

通过这种方式,你可以轻松地管理中间件之间的依赖关系,确保它们按顺序执行,并且每个中间件都能访问到所需的依赖。


中间件要安排好流程顺序就行,过多的依赖会造成维护困难,这么注入不还是链式执行。

你这个模块会不会遇到跟 npm 一样的重复依赖问题?

比如 a 和 b 都依赖 c,那么我在 a 和 b 的声明中都写了 c,这样 c 会不会被执行两次?

不会,重复的依赖只会执行一次,这也是这个工具的意义。

我是打算在应用层重度使用中间件模式的,所以不可避免地会遇到依赖管理的问题,这个工具会保证对于每个请求只会执行需要用到的中间件,并且每个中间件只执行一次。

cool …

怎么着都不如直接在app.js里先后顺序的定义来的一目了然。。。你真的需要那么多中间件么?

先后顺序其实就行了,不过这个di的想法有点意思

di 还是使用强大的 bearcat

如果是这样,那么你应该要有更好的设计,而不是依赖于工具去解决。

你的 book 是不是就几个 url 用到?

这个 middleware-injector 工具允许你在 Express 中间件之间定义依赖关系,并按顺序执行这些中间件。下面是一个简化的版本,展示了如何使用这个工具来管理中间件的依赖。

首先,确保你已经安装了这个库:

npm install middleware-injector

接下来,我们来看看如何使用这个库。以下是一个简单的例子,展示了如何定义和注入中间件依赖:

示例代码

假设我们有以下几个中间件:

  • parseToken: 解析并设置请求中的 token。
  • accountInfo: 验证账户信息。
  • errorHandling: 处理错误。
const express = require('express');
const injector = require('middleware-injector');

const app = express();

// 定义中间件
const parseToken = (req, res, next) => {
  req.token = req.cookies.token;
  next();
};

const accountInfo = (req, res, next) => {
  req.inject([parseToken], () => {
    // 假设 mAccount 是一个验证 token 的对象
    mAccount.authenticate(req.token, (account) => {
      req.account = account;
      next();
    });
  });
};

const errorHandling = (req, res, next) => {
  res.error = (name, param) => {
    param = { ...param, error: name };
    res.status(400).json(param);
  };
  next();
};

const requestAuthenticate = (req, res, next) => {
  req.inject([accountInfo, errorHandling], () => {
    if (req.account) {
      next();
    } else {
      if (req.method === 'GET') {
        res.redirect('/account/login/');
      } else {
        res.error('auth_failed', {});
      }
    }
  });
};

// 使用中间件
app.use(injector());
app.use(parseToken);
app.use(accountInfo);
app.use(errorHandling);
app.use(requestAuthenticate);

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

解释

  1. 定义中间件: 我们定义了几个中间件函数,每个中间件都处理特定的任务。
  2. 注入依赖: 在 accountInforequestAuthenticate 中,我们使用 req.inject 方法来注入依赖。例如,在 accountInfo 中,我们先解析 token,然后再验证账户信息。
  3. 使用中间件: 最后,我们将中间件添加到 Express 应用中,并使用 injector() 来管理依赖关系。

通过这种方式,我们可以更方便地管理和组织中间件之间的依赖关系,使得代码更加清晰和易于维护。

回到顶部