【问题标题】:Node ExpressJS: middleware URL route response vs route destinationNode ExpressJS:中间件 URL 路由响应与路由目的地
【发布时间】:2021-06-25 07:09:52
【问题描述】:
router.use((req, res, next) => {
    if(req.originalUrl == '/api/test'){
        //does stuff
        res.send(result);
    }
    next();
})

对

route.get('/api/test', (req, res) => {
   //does stuff
   res.send(result)
}

我对整个 HTTP Web 应用程序的安全行为相当陌生,所以我想问一下,如果我使用第一种方法来解决某些路由目的地,是否有任何漏洞或缺点?

【问题讨论】:

    标签: javascript node.js api express


    【解决方案1】:

    我对整个 HTTP Web 应用程序的安全行为相当陌生,所以我想问一下,如果我使用第一种方法来解决某些路由目的地,是否有任何漏洞或缺点?

    router.use() 和 router.get() 之间有两个主要区别,其中一个在这里有些相关:

    1. router.use() 匹配任何 http 动词,例如 GET、POST、PUT、OPTION、PATCH 等……而 router.get() 仅匹配 GET 请求,router.post() 仅匹配 POST 请求等。

    2. router.use() 使用“松散”匹配算法,其中请求的路由只需从路由上的路径指定开始,而不是完全匹配。

    对于第一点,您的中间件处理程序正在为所有请求路径为 /api/test 的 http 动词执行 res.send(response)。这可能不是您想要的,也不是您应该如何编写代码。您应该让您的代码仅响应您实际打算支持的路径的 http 动词并做一些有用的事情。其他动词可能应该以 4xx 状态代码响应(如果您没有处理程序,这将是 Express 中的默认值)。

    对于第二点,您的中间件处理程序是通用的(未设置路径)并且您已经在检查整个路径,因此该点不相关。

    加上一点点,我想说你的中间件方法很好。我会为req.method添加支票:

    router.use((req, res, next) => {
        if(req.method === "GET" && req.originalUrl == '/api/test'){
            //does stuff
            res.send(result);
            // return so the rest of the route handler is not executed
            // and we don't call next()
            return;
        }
        next();
    });
    

    说了这么多,你也可以用更通用的方式解决你的问题。例如,如果您在此中间件前面放置一个特定的路由定义,那么它将自动从中间件中排除,因为它会在中间件运行之前得到处理。 Express 中的路由按照声明的顺序进行匹配和运行。

    router.get('/api/test', (req, res) => {
       //does stuff
       res.send(result)
    });
    
    router.use((req, res, next) => {
        // do some middleware prep work on all requests that get here
        // ...
        next();
    });
    
    // other route definitions here that can use the results of the prior middleware
    

    例如,如果您有一些需要身份验证而其他不需要身份验证的路由,这很常见。您首先放置未经过身份验证的路由,然后放置身份验证中间件,然后定义要在身份验证检查之后的路由。

    【讨论】:

    • 您的回答正是我所需要的。你的第一点是一个很好的补充,我肯定会更加意识到这一点。至于第二点,不知道我从哪里得到中间件总是首先执行的误解,但你的提醒确实解决了我的误解。最初提出的问题正是因为我正在尝试进行身份验证相关的应用程序,而您的回答很有帮助。
    • @Aii - 注意一个编辑,我刚刚添加。在中间件中调用res.send()后,需要return,这样代码就不会继续执行,调用next()。很高兴这是您所需要的。
    • 我还想问一下,有没有办法插入一个中间件,在每个选定的路由结束时触发?
    • @Aii - 我不知道,但是日志记录可能使用某种机制来跟踪何时发送可能被黑客入侵的响应。
    【解决方案2】:

    没有“确切的”漏洞,但有很多很多缺点。这里的主要区别在于第一段代码是我们所说的“全局处理程序”。它在每个请求上执行。第二段只是具体的路线。

    当您发出请求时,express 开始评估它需要执行的操作以返回响应的管道。首先,它执行所有全局处理程序(如第一个示例)。然后它开始将路由与处理程序列表进行匹配,如果找到它 - 它会执行该函数。

    使用第一种方法的风险是破坏链并且不能正确执行所有全局/本地处理程序。其中一些可能会做特定的事情(比如防止你受到某种类型的攻击)。然后,使用第二种方法,您可以定义更多的东西,而不仅仅是一个全局处理程序:您定义端点以及方法(在您的情况下,它是一个 GET 请求)。

    当匹配器找到您的路线时,它会自动为您断开链接(在最简单的情况下)。

    还请注意,在第一个示例中,您将有一个包含大量 if-else 语句的单点来确定您想对该请求执行什么操作。它基本上减轻了快递的需求......


    Express 的制作方式支持多个“中间件”。如果你想根据一些动作来做特定的部分,你可以这样做:

    router.get('/users',
      handler1(req, res, next) {
        if (req.something) {
          next(); // we skip the logic here, but we go to handler2
        } else {
          // do your magic
          res.send(response);
        }
      },
      handler2(req, res, next) {
        // you skipped the action from handler1
        res.send(anotherResponse); // you MUST send a response in one handler
      }
    

    【讨论】:

    • 您总是可以使用多个中间件处理程序,这就是 express 的用途! :) 我已经更新了我的答案
    • 感谢您的回复。我目前正在努力实现的目标是让特定的行动免于处理程序。由于没有办法在处理程序之前放置一个单一的目标路由,所以我使用了第一种方法。如下:router.use((req, res, next) => {//typical handler action})router.use((req, res, next) => {//exceptionif(url){res.send();res.send();}//typical handler actionnext();})
    • 你可以很容易地做到这两点,但我强烈建议你不要使用你的方法。您可以拥有router.use(不是全局的,而是每个路由器),还可以添加用于测试的路由单独像if (testing) { app.use('/tests', testRouter) }
    猜你喜欢
    • 2016-05-31
    • 2023-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-07
    • 2021-09-06
    • 1970-01-01
    相关资源
    最近更新 更多