在不修改 NodeBB 代码的情况下,我能找到的唯一解决方案是将中间件插入到一个方便的钩子中(这将比您想要的晚),然后侵入应用程序路由器中的层列表以将该中间件移到应用程序层列表中的前面把它放在你想放在前面的东西前面。
这是一个 hack,因此如果 Express 在未来某个时间更改其内部实现,那么这可能会中断。但是,如果他们改变了这部分实现,它可能只会在一个主要版本中(如在 Express 4 ==> Express 5 中),您可以调整代码以适应新方案,或者 NodeBB 可能会给出到那时你是一个合适的钩子。
基本概念如下:
- 获取您需要修改的路由器。看来它是
app
您想要的 NodeBB 路由器。
- 像往常一样插入您的中间件/路由,以允许 Express 为您的中间件/路由进行所有正常设置,并将其插入应用程序路由器的内部层列表中。
- 然后,进入列表,将其从列表末尾(刚刚添加的位置)取出并将其插入到列表的前面。
- 弄清楚在列表中较早的位置放置它。您可能不希望它位于列表的最开头,因为这会将它放在一些有用的系统中间件之后,这些中间件可以使查询参数解析等工作正常进行。因此,代码会从我们知道的内置名称中查找第一个具有我们无法识别的名称的中间件,然后将其插入。
这是插入中间件的函数的代码。
function getAppRouter(app) {
// History:
// Express 4.x throws when accessing app.router and the router is on app._router
// But, the router is lazy initialized with app.lazyrouter()
// Express 5.x again supports app.router
// And, it handles the lazy construction of the router for you
let router;
try {
router = app.router; // Works for Express 5.x, Express 4.x will throw when accessing
} catch(e) {}
if (!router) {
// Express 4.x
if (typeof app.lazyrouter === "function") {
// make sure router has been created
app.lazyrouter();
}
router = app._router;
}
if (!router) {
throw new Error("Couldn't find app router");
}
return router;
}
// insert a method on the app router near the front of the list
function insertAppMethod(app, method, path, fn) {
let router = getAppRouter(app);
let stack = router.stack;
// allow function to be called with no path
// as insertAppMethod(app, metod, fn);
if (typeof path === "function") {
fn = path;
path = null;
}
// add the handler to the end of the list
if (path) {
app[method](path, fn);
} else {
app[method](fn);
}
// now remove it from the stack
let layerObj = stack.pop();
// now insert it near the front of the stack,
// but after a couple pre-built middleware's installed by Express itself
let skips = new Set(["query", "expressInit"]);
for (let i = 0; i < stack.length; i++) {
if (!skips.has(stack[i].name)) {
// insert it here before this item
stack.splice(i, 0, layerObj);
break;
}
}
}
然后,您将使用它从任何 NodeBB 钩子中插入您的方法,该钩子app
在启动期间的某个时间为您提供对象。它将创建您的/webhook
路由处理程序,然后将其插入到层列表的前面(在其他主体解析器中间件之前)。
let rawMiddleware = bodyParser.raw({type: 'application/json'});
insertAppMethod(app, 'post', '/webhook', (request, response, next) => {
rawMiddleware(request, response, (err) => {
if (err) {
next(err);
return;
}
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
// you need to either call next() or send a response here
} catch (err) {
return response.status(400).send(`Webhook Error: ${err.message}`);
}
});
});