基于子域创建池中间件 - 连接太多
Create Pool middleware based on subdomain - Too many connections
想法是,基于子域 ex。 tenant1.app.com
或 tenant2.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(),这有点复杂,因为我必须事先了解数据库而不是即时进行。
它的工作原理是...
- 在
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));
- 从中间件的池中提取一个连接。
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();
});
});
};
};
- 使用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();
}
});
看来效果不错,如果有人发现问题,请回复。
想法是,基于子域 ex。 tenant1.app.com
或 tenant2.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(),这有点复杂,因为我必须事先了解数据库而不是即时进行。
它的工作原理是...
- 在
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));
- 从中间件的池中提取一个连接。
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();
});
});
};
};
- 使用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();
}
});
看来效果不错,如果有人发现问题,请回复。