基于子域创建池中间件 - 连接太多

Create Pool middleware based on subdomain - Too many connections

想法是,基于子域 ex。 tenant1.app.comtenant2.app.com 应用程序连接到相应的数据库。

数据库名称在身份验证期间存储在 JWT 中。

这是处理这个用例的正确方法吗?

middleware.js

let authenticationHandler = (req, res, next) => {
    
    let token = req.headers.authorization;

    jwt.verify(token, "tracer", (err, decoded) => {
        if (err) {
            res.status(401).send({message: "Access denied"});
        } else {
            req.decoded = decoded;     // <------ the token is passed to database middleware
            next();
        }
    });
};

let databaseHandler = (req, res, next) => {
    let database = req.decoded.database;

    let util = require("util");

    let pool = mysql.createPool({
        ...db,
        database: database,
    });

    pool.query = util.promisify(pool.query);

    req.pool = pool;             // <------ pool is passed to API

    next();
};

app.all("/api/*", middleware.authenticationHandler);
app.all("/api/*", middleware.databaseHandler);

api.js

router.get("/api/products", async function (req, res, next) {
    try {
        let query = `select * from product;`;

        var rows = await req.pool.query(query);            // <------ the pool is used
        res.status(200).send(rows);
    } catch (err) {
        next(err);
    }
});

我最终选择了 方法来实现我想要的。

另一个选择是 mysql.createPoolCluster(),这有点复杂,因为我必须事先了解数据库而不是即时进行。

它的工作原理是...

  1. server.js 中创建一个主池。
// One main pool is created on app initialization
let pool = mysql.createPool(db);
// That pool is passed in the database middleware
// which forwards a connection to a corresponding database for further use
app.all("/api/*", middleware.databaseHandler(pool));
  1. 从中间件的池中提取一个连接。
let databaseHandler = (pool) => {
    return (req, res, next) => {
        // req.decoded comes from authenticationHandler
        let database = req.decoded.database;

        // Get a connection from the main pool in app.js
        pool.getConnection((err, conn) => {
            if (err) {
                console.log(err);
                return;
            }
            // Change the database for the connection
            conn.changeUser({ database: database }, function (err) {
                if (err) {
                    console.log(err);
                    return;
                }

                // Promisify for Node.js async/await.
                const query = util.promisify(conn.query).bind(conn);

                // Pass the modified query method down the chain as a property of req, avaiable via next()
                // connection.release() is called in the routes
                req.query = query;
                req.connection = conn;
                next();
            });
        });
    };
};
  1. 使用API中的连接,然后释放。
router.get("/api/products", async function (req, res, next) {
    try {
        let query = `select * from product;`;

        var rows = await req.query(query);
        res.status(200).send(rows);
    } catch (err) {
        next(err);
    } finally {
        req.connection.release();
    }
});

看来效果不错,如果有人发现问题,请回复。