【问题标题】:How can I wrap every every express route handler with another function如何用另一个函数包装每个快速路由处理程序
【发布时间】:2016-10-10 12:39:37
【问题描述】:

基本上我想代替这个...

app.get(routes.test, function(req, res, next){
  actualRouteHandler(req, res, next) // Always returns a promise or throws.
    .catch(function(err) {
      next(err);
    });
});

有这个: app.get(routes.test, catchWrap(actualRouteHandler));

或类似的东西,我尝试过处理 fn.apply 之类的东西,但我找不到向实际路由处理程序传递正确参数(req、res、next)并且仍然具有该功能的方法。我需要返回一个函数或类似的东西吗?

编辑:我认为可能存在执行此操作的库,但在这段代码中我们无法访问实际的 express 应用程序。

【问题讨论】:

  • 我的印象是 app.use 是用于中间件的,我基本上只是想将每个控制器的处理程序包装在一个小函数中,然后将任何捕获的异常传递给我的实际错误处理中间件。
  • 比如说我在问如何使用事件处理程序来做到这一点,你知道怎么做吗?例如el.addEventListener('click', handleFunction) 但是然后将handleFunction 包装在另一个函数中,该函数说...在另一个函数周围添加一个try/catch 块,或者添加一些其他功能。不一定要跟express有关,就是不知道怎么用这种方式给函数传其他参数。
  • 不,我们可以随意添加中间件和路由,但不能说...使用 Express Promise Router (npmjs.com/package/express-promise-router),因为我们无法访问实际的 express 应用程序,我们只能建立在它的基础上,这远非理想。
  • 哦,酷,我可以回答这个问题! :-)

标签: javascript node.js function express apply


【解决方案1】:

在您的具体情况下,catchWrap 看起来像这样:

function catchWrap(originalFunction) {
    return function(req, res, next) {
        try {
            return originalFunction.call(this, req, res, next);
        } catch (e) {
            next(e);
        }
    };
}

这会返回一个新函数,当调用该函数时,它将调用带有你的 catch 包装器的原始函数。关键部分是它创建并返回一个函数(return function(req, res, next) { ... };)和这一行:

return originalFunction.call(this, req, res, next);

Function#call 调用给定函数,说明在调用期间使用 this 的内容(在上面我们传递收到的 this)以及在调用中使用的参数。

你会按照你展示的那样使用它:

app.get(routes.test, catchWrap(actualRouteHandler));

或者,如果您更愿意将实际处理程序定义为匿名函数:

app.get(routes.test, catchWrap(function(req, res, next) {
    // ...handler code here...
}));

catchWrap 特定于您的情况,因为如果抛出异常,您想调用 next(e)。 “将此函数包装在另一个函数中”的通用形式是这样的:

function catchWrap(originalFunction) {
    return function() {
        try {
            // You can do stuff here before calling the original...
            // Now we call the original:
            var retVal = originalFunction.apply(this, arguments);
            // You can do stuff here after calling the original...
            // And we're done
            return retVal;
        } catch (e) {
            // you can do something here if you like, then:
            throw e; // Or, of course, handle it
        }
    };
}

arguments 是 JavaScript 提供的伪数组,其中包含调用当前函数的所有参数。 Function#apply 就像 Function#call 一样,只是你提供的参数用作数组(或伪数组)而不是离散的。

【讨论】:

  • 太棒了,在这样的时刻,你真的想知道为什么你自己没有想到这些事情,你把事情变得非常简单,干杯。我唯一要问的是关于传递this,这是否意味着当我在originalFunction 中引用它时,它将使用外部函数中的this?如果我不需要使用this,我可以正常调用该函数吗?
  • 按照上面的写法,它将使用 Express 在调用我们的包装器时使用的 this(匿名函数 catchWrap 返回)。因此,如果 Express 使用了特定的this,我们将其传递;如果 Express 只是调用函数而不做任何设置 thisthis 将是全局对象(在松散模式下)或 undefined(在严格模式下),我们再次传递它。所以originalFunction.call(this, ...) 的一般模式通常是最好的。但是,如果您知道 originalFunction 不期待任何特定的 this,是的,您可以直接调用它。
【解决方案2】:

以下简单方法可用于设置通用错误处理程序 -

第 1 步:在注册路由后编写错误处理程序。因此,例如,如果您要像这样注册多个路线:

config.getGlobbedFiles('./app/routes/modules/**/*.js').forEach(function (routePath) {
        require(path.resolve(routePath))(app);
    });

注册路由后,您可以设置通用错误处理程序 -

app.use(function (err, req, res, next) {

        // If the error object doesn't exists
        if (err != undefined) {
            //do error handling
        }
        else {
            //no error found
        }

    }); 

第 2 步:在路由处理程序中,如果没有发现错误,您需要确保调用“next()”。如果出现错误,您需要调用“next(err)”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-04
    • 2022-01-01
    • 2020-11-13
    • 1970-01-01
    • 2013-05-23
    • 2019-02-03
    相关资源
    最近更新 更多