【问题标题】:Can I have an Express middleware that runs after the router but before the route handler?我可以有一个在路由器之后但在路由处理程序之前运行的 Express 中间件吗?
【发布时间】:2022-02-13 09:02:57
【问题描述】:

我想要一个通用中间件,它可以采用“req.route.path”值(例如“/foo/:id”而不是实际的 URL 值“/foo/123”)并在 HTTP 响应标头中返回它称为“X-ROUTE-NAME”。这个想法是让这个路由值被单独的日志/度量基础设施记录和记录,并允许路由名称上的“分组依据”用于以后的其他分析目的。

这是我的第一次尝试:

app.use(function(req, res, next) {
  const {path} = req.route;
  console.log("The path was:", path);
  res.setHeader("X-ROUTE-NAME", req.route.path);
  next();
});

它不起作用,因为如果你在注册路由之前放置它,它在req.route.path 中还没有任何值。但是,如果您在路由之后注册它,如果处理程序已经在 req 上发送了内容,那么当您尝试设置标头时会出现异常。

所以,是的,棘手的部分是弄清楚如何在路由器设置“req.route.path”值之后(并将其作为标头保存到响应中),但在处理程序拾取它之前(因为处理程序可以根据需要发送内容,然后您将无法再设置标题)。

有什么想法吗?

【问题讨论】:

  • 什么 routers.middleware 负责添加req,route?你能说明你是如何注册的吗?
  • 我正在使用 express.Router。比如:const router = express.Router(); router.get(“/foo/:fooId”, someHandler);。这里的关键是我想将它作为我公司内部的共享中间件库发布。
  • 好的,你能在注册所有路由器的地方添加代码并指出你需要中间件的地方吗?
  • 想象一下像上面这样的多个router.get 调用,我想要一个中间件来添加所需的标头,而不管哪个路由被解析。
  • router.use(yourMiddleWare) 也不起作用? router.get(“/foo/:fooId”, yourMiddleware, someHandler);呢?

标签: node.js express


【解决方案1】:

使用这样的东西:

router.use(routerModule) 路由到主文件中的路由器模块。
并在路由器模块中使用 router.get('/path', yourroute, actualCodeToBeExecuted)

这样,您的 yourroute 在路由器之后但在实际的功能路由之前被调用。

希望这行得通!

【讨论】:

  • “routerModule”和“yourroute”分别代表什么?
【解决方案2】:
app.use(function(req, res, next) {
  const {path} = req.route;
  console.log("The path was:", path);
  
  next();
  res.setHeader("X-ROUTE-NAME", req.route.path);
});

移动 setHeader 应该会有所帮助

【讨论】:

    【解决方案3】:

    我找到了适合我的解决方案:

    // create a test router and handler
    const testRouter = express.Router();
    
    testRouter.get('/test/:testId', (req, res) => {
      console.log("HANDLER");
      res.send("{}")
    });
    
    // create a function that injects a "beforeHandle" function into a router instance (depends on a private interface though)
    function onBeforeHandle(router: IRouter, beforeHandle: (req: Request, res: Response) => void) {
      const methodName = "process_params";
      const routerAny: any = router;
      const oldFn = routerAny[methodName];
      
      if (!oldFn) {
        throw new Error(`No private '${methodName}' method found on router. This may be an incompatible version of Express.`);
      }
      
      if (oldFn.length !== 5) {
        throw new Error(`Invalid number of arguments on private '${methodName}' method. This may be an incompatible version of Express.`);
      }
    
      const newFn = (...args: any[]) => {
        const [, , req, res, handler] = args;
    
        beforeHandle(req, res);
        return oldFn.apply(routerAny, args as any);
      }
      routerAny[methodName] = newFn;
    }
    
    // function to be executed prior to the route handler
    function setRouteNameHeader(req: Request, res: Response) {
      const routeHeaderName = "Q-ROUTE-NAME";
      if (!req.route) {
        console.log(`Can't add '${routeHeaderName}' header as 'req.route' is not set.`);
      } else {
        if (!res.headersSent) {
          res.setHeader(routeHeaderName, req.route.path);
        } else {
          console.log(`Can't add '${routeHeaderName} ${req.route.path}' header as headers were already sent.`);
        }
      }
    }
    
    // actually inject the function
    onBeforeHandle(testRouter, setRouteNameHeader);
    

    【讨论】:

      猜你喜欢
      • 2016-03-11
      • 2018-06-18
      • 2015-01-10
      • 2019-01-24
      • 2014-11-21
      • 1970-01-01
      • 2020-10-05
      • 2015-11-16
      • 1970-01-01
      相关资源
      最近更新 更多