手动呼叫Express路由器

时间:2019-02-13 18:13:13

标签: node.js performance express

Нello!我希望调用已传递给expressRouter.post(...)调用的函数。

expressRouter.post(...)调用发生在我我无法修改的文件中。该代码已经分发给许多客户端,并且没有任何程序可以修改它们的文件版本。虽然 I 无法为远程客户端更新此文件,但其他开发人员却可以。因此,我面临着将来该POST端点的行为发生变化的问题。

我也在处理性能问题。该POST端点期望req.body是已解析的JSON对象,并且该JSON对象可能过大。

我的目标是编写一个GET端点,该端点在内部激活该POST端点。 GET端点将需要使用非常大的JSON值调用POST端点,该JSON值已插入URL查询参数。 GET的功能应始终反映POST的功能,包括将来是否更新POST的功能。因此,我无法复制/粘贴POST的逻辑。还要注意,JSON格式永远不会改变。

我了解,通常通过1){extracting the router function into an accessible scope或2)generating an HTTP request to localhost解决了内部调用expressjs端点的问题。

不幸的是,在我看来,这些选项都不可行:

  1. 由于无法修改源代码,因此无法将功能移入可访问范围,也不能复制粘贴功能,因为原始版本可能会更改
  2. 出于性能考虑,避免HTTP请求是高优先级。 HTTP请求将需要序列化+反序列化一个过大的JSON主体,重新访问许多身份验证中间件(需要等待进一步的HTTP请求+数据库查询完成),等等

这是我的(人为)POST端点:

expressRouter.post('/my/post/endpoint', (req, res) => {

  if (!req.body.hasOwnProperty('val'))
    return res.status(400).send('Missing "val"');

  return res.status(200).send(`Your val: ${req.body.val}`);

});

如果我向localhost:<port>/my/post/endpoint发出POST请求,则会根据是否在JSON正文中包含“ val”而得到预期的错误或响应。

现在,我希望具有完全相同的可用功能,但要通过GET,并在URL中而不是任何JSON正文中提供“ val”。我尝试了以下操作:

expressRouter.get('/my/get/endpoint/:val', (req, res) => {

  // Make it seem as if "val" occurred inside the JSON body
  let fakeReq = {
    body: {
      val: req.params.val
    }
  };

  // Now call the POST endpoint
  // Pass the fake request, and the real response
  // This should enable the POST endpoint to write data to the
  // response, and it will seem like THIS endpoint wrote to the
  // response.
  manuallyCallExpressEndpoint(expressRouter, 'POST', '/my/post/endpoint', fakeReq, res);

});

很遗憾,我不知道如何实现manuallyCallExpressEndpoint

是否有解决此问题的方法,该方法既不将函数提取到可访问的范围内,又不生成HTTP请求?

2 个答案:

答案 0 :(得分:1)

一个简单的中间件怎么样?

function checkVal(req, res, next) {
  const val = req.params.val || req.body.val

  if (!val) {
    return res.status(400).send('Missing "val"'); 
  }

  return res.status(200).send(`Your val: ${val}`);
}

app.get('/my/get/endpoint/:val', checkVal)
app.post('/my/post/endpoint', checkVal)

此代码未经测试,但让您大致了解如何在两个地方运行相同的代码。

checkVal函数用作Express处理程序,带有请求,响应和下一个。首先检查参数,然后检查身体。

答案 1 :(得分:1)

这似乎可行,但是修改req并传递它而不是创建一个全新的fakeReq对象可能更有意义。启用此功能的是router.handle(req, res, next)函数。我不确定这是解决问题的最明智的方法,但是它肯定会避免单独的http请求的大量开销!

app.get('/my/get/endpoint/:val', (req, res) => {

  // Modify `req`, don't create a whole new `fakeReq`
  req.body = {
    val: req.params.val
  };

  manuallyCallExpressEndpoint(app, 'POST', '/my/post/endpoint', req, res);

});

let manuallyCallExpressEndpoint = (router, method, url, req, res) => {
  req.method = method;
  req.url = url;
  router.handle(req, res, () => {});
};