具有仅发生一次的异步操作的 Express 中间件

Express middleware with async operation that happens only once

我正在尝试使用中间件将一些数据附加到我的请求对象,但我只想在服务器启动后执行此操作。 所以我尝试用中间件来做,同时尝试使用函数的上下文,但是在中间件上执行这样的操作有点问题,因为我不能将承诺作为中间件传递。

这就是我想要做的:

const setupData = async () => {
    const data = await getSomeData();
    return (req, res, next) => {
        req.data = data;
        next();
    }
}

app.use(setupData());

我尝试使用建议的解决方案 ,但它不起作用,因为每次请求都会发生这种情况。

知道我该如何解决这个问题吗?我总是可以将信息放在全局变量中,但我想避免它。 我还看到了一些内存包来帮助它(例如node-cache),但我想用中间件来做。

提前致谢

你可以在没有异步的情况下做到这一点:-

const setupData = (req, res, next) => {

// You can put a condition here so that it runs only once
    getSomeData().then((data) => {
    req.app.locals.data = data //The data can be accessed in the next middleware using req.app.locals
    next();
}).catch((error) => {
console.log("Error Occured");
res.status(400).end("Error Occurred");
})
}
app.use(setupData);

您应该查看 getSomeData 的文档并了解其工作原理

只需使用普通变量缓存结果:

let data = null;

function setupData (req, res, next)  {
    if (data !== null) {
        req.data = data;
        next();
    }
    else {
        getSomeData().then(result => {
            data = result
            req.data = data;
            next();
        });
    }
}

app.use(setupData);

这是最小的、最不复杂的实现。您当然可以通过删除缓存逻辑将其重构为更干燥并且更不容易出错:

更简洁的实施

let cache = null;
async function getCachedData() {
    if (cache === null) {
        cache = await getSomeData();
    }
    return cache;
}

这使得 setupData 更干净:

function setupData (req, res, next) {
    getCachedData().then(data => {
        req.data = data;
        next();
    });
}

无论哪种方式,都会在第一次请求时触发缓存。这意味着有可能在数据可能被缓存之前第二个请求到达。所以在启动时 getSomeData() 函数可能 运行 不止一次。

真的只调用一次 getSomeData()

如果您真的只想调用 getSomeData 一次,您 必须 在设置 Express 之前调用它:

async function main () {

    const data = await getSomeData();

    const app = express();

    //
    // set up express middlewares...
    //

    app.use((req,res,next) => {
        req.data = data;
        next();
    });

    //
    // set up routes...
    //

    app.listen(config.port);
}

main(); // start everything

这里的关键是要意识到我们一直在尝试向后做所有事情:异步设置一个常量值 开始设置 Express 之后。程序的自然流程希望常量值存在 BEFORE 我们开始设置 Express,因此我们只在异步函数(此处称为 main)中执行其他所有操作。在设置 Express 时不要尝试 运行 异步功能。