【问题标题】:How to use global error handling code in node.js for entire api call如何在 node.js 中使用全局错误处理代码进行整个 api 调用
【发布时间】:2013-10-13 11:39:47
【问题描述】:

我有一个具有多个功能的 api 调用。除了对每个方法都应用错误处理之外,是否可以使用将错误发送给 UI 开发人员的全局错误处理代码。

代码如下:

app.post('/billing/pricingdetails', function (req, res) {
    console.log('pricing api called');
    var workload = req.body;
    var resourcelevelPricing = {};
    var response = {};
    var workloadinfo = {
        workloadId: workload.workloadId,
        ownerId: workload.ownerId,
        uniqueName: workload.uniqueName,
        name: workload.name
    }
    var pricing = {}
    var allresourceIdentifiers;

    if (workload.elements && workload.elements.length > 0) {
        var elementlevelpricingSummary = {};
        var elementArray = [];
        var allresourceIdentifierArray = [];
        var elementinfo = {};
        var metadataModified = {};
        var elementsParam = workload.elements;
        // handle configurable resource
        var configurableElementarray = [];

        // create array of all the elements in workloadjson - to be used for resourcelevel (instance/image), charamountunitlevel, resourcetypelevel pricing detail
        for (var index in elementsParam) {
            // if condition skips the uri of configurable resources - handle configurable resource
            if(!elementsParam[index].parameters.ResourceParameters) 
            {
                allresourceIdentifierArray.push(elementsParam[index].uri);

                if (elementsParam[index].parameters.imageUri) {
                allresourceIdentifierArray.push(elementsParam[index].parameters.imageUri);
                }
            }
        }

        var allresourceIdentifiers = allresourceIdentifierArray.join(',');

        // call the functionalities that gives the each level of pricing detail synchronously to construct the workload json 
        async.series([
        function (callback) {

            getpricingSummary(elementsParam, function (err, workloadinfo) {
                if(err){

                }
                else
                {
                callback(null, workloadinfo);
                }

            });
        },
        function (callback) {

            getPricingforResourceIdentifiers(allresourceIdentifiers, function (err, pricingDetail) {

                pricing.resourceLevel = pricingDetail;
                callback(null, pricingDetail);

            });
        },
        function (callback) {

            getchargeamountunitlevelPricing(allresourceIdentifiers, function (err, pricingDetail) {

                //merge configurable resource with concrete resource pricing details - handle configurable resource
                if(configurableElementarray.length > 0)
                {

                    var concatednatedArray = pricingDetail.concat(configurableElementarray);

                    var finalResult = [];

                    var i = concatednatedArray.reduce(function (result, o) {

                    var key  = o.chargeAmountUnit + o.currencyCode;

                    if (!(key in result)) {
                    result.arr.push(result[key] = o);
                    finalResult.push(result);
                    } 

                    else {
                    result[key].chargeAmount += Number(o.chargeAmount);
                    }

                    return result;
                    }, { arr: [] }).arr;

                    pricing.chargeamountunitLevel = i;

                    trace.info(i);

                }
                else
                {
                    pricing.chargeamountunitLevel = pricingDetail;  
                }
                callback(null, pricingDetail);

            });
        },
        function (callback) {

            getresourcetypelevelPricing(allresourceIdentifiers, function (err, pricingDetail) {

                if(configurableElementarray.length > 0)
                {

                    var concatednatedArray = pricingDetail.concat(configurableElementarray);

                    var i = concatednatedArray.reduce(function (result, o) {

                    var key  = o.chargeAmountUnit + o.currencyCode + o.Name;

                    if (!(key in result)) {
                    result.arr.push(result[key] = o);
                    } 

                    else {
                    result[key].chargeAmount += o.chargeAmount;
                    }

                    return result;
                    }, { arr: [] }).arr;

                    pricing.resourcetypeLevel = i;
                    trace.info(i);

                }
                else
                {
                    pricing.resourcetypeLevel = pricingDetail;
                }
                callback(null, pricingDetail);

            });
        }
        ],
        function (err, result) {

            workloadinfo.pricing = pricing;
            res.send(workloadinfo);

        });

        // get element level pricing summary for each elements (vm/vs) in the array within workload json - the output to be appended within metadata of workload json
        function getpricingSummary(elementsParam, callback) {

            async.forEachSeries(elementsParam, createResponse, function (err,result) {

                return callback(null, result);

            });
        };

        // this method called by async.forEachSeries passing each elements (vm/vs) of workload
        function createResponse(elements, callback) {

            var resourceIdentifierArray = [];

            elementinfo = elements;

            resourceIdentifierArray.push(elements.uri);

            if (elements.parameters.imageUri) {

                resourceIdentifierArray.push(elements.parameters.imageUri);
            }

            // build string of resourceIdentifier (instance/image) for input element
            var resourceIdentifiers = resourceIdentifierArray.join(',');

            console.log(resourceIdentifiers);

            if(elements.parameters.ResourceParameters)
            {
                trace.info('1');

                trace.info(elements.parameters.ResourceParameters);

                var configJson = JSON.parse(elements.parameters.ResourceParameters);

                trace.info(Number(configJson.cpuCount));

                metadataModified = elements.metadata;

                // TODO : Remove this hard-coding
                elementlevelpricingSummary.Name = 'Hardware';

                if(configJson.totalUnitPrice)
                {
                    var chargeAmount = configJson.totalUnitPrice;

                    elementlevelpricingSummary.chargeAmount = Math.round(chargeAmount * 100)/100;
                }
                if(configJson.ChargeAmountUnit)
                {
                    var chargeAmountUnit = configJson.ChargeAmountUnit;

                    elementlevelpricingSummary.chargeAmountUnit = configJson.ChargeAmountUnit;
                }
                if(configJson.CurrencyCode)
                {
                    var currencyCode = configJson.CurrencyCode;

                    elementlevelpricingSummary.currencyCode = configJson.CurrencyCode;
                }   

                metadataModified.pricingSummary = elementlevelpricingSummary;

                configurableElementarray.push(elementlevelpricingSummary);

                // delete original metadata from workload json (to be replaced by metadata containing pricing summary)
                delete elementinfo.metadata;

                elementinfo.metadata = metadataModified;

                elementArray.push(elementinfo);

                // global workloadinfo variable is appended with array of elements with its pricing summary within metadata of respective elements
                workloadinfo.elements = elementArray;

                return callback();
            }

            else
            {
                // Get element level pricing summary
                mysql.elementlevelpricing(resourceIdentifiers, conn, function (result) {

                elementlevelpricingSummary = result;

                metadataModified = elements.metadata;

                metadataModified.pricingSummary = elementlevelpricingSummary;

                // delete original metadata from workload json (to be replaced by metadata containing pricing summary)
                delete elementinfo.metadata;

                elementinfo.metadata = metadataModified;

                elementArray.push(elementinfo);

                // global workloadinfo variable is appended with array of elements with its pricing summary within metadata of respective elements
                workloadinfo.elements = elementArray;

                return callback(null,workloadinfo);

                });
            }
        };

        function getPricingforResourceIdentifiers(resourceIdentifiers, callback) {

            mysql.pricingDetail(resourceIdentifiers, conn, function (result) {

                return callback(null, result);

            });
        };

        function getchargeamountunitlevelPricing(resourceIdentifiers, callback) {

            mysql.chargeamountunitlevelPricing(resourceIdentifiers, conn, function (result) {

                return callback(null, result);

            });
        };

        function getresourcetypelevelPricing(resourceIdentifiers, callback) {

            mysql.resourcetypelevelPricing(resourceIdentifiers, conn, function (result) {

                return callback(null, result);

            });
        };

    };

});

【问题讨论】:

    标签: javascript node.js error-handling


    【解决方案1】:

    使用 Express,您可以安装一个错误处理程序,当您的任何路线发生错误时将调用该处理程序:

    // somewhere at the end of your middleware/route chain
    app.use(function(err, req, res, next) {
      res.send(500, err.message); // or whatever you want to send back
    });
    

    最好还是重新抛出代码中出现的任何错误:

    if (err) throw err;
    

    此外,由于您使用的是async,因此您始终可以将错误传播回它:

    if (err) return callback(err);
    

    并在最终回调中处理错误。

    【讨论】:

    • 我的代码中有它,但它似乎不起作用:app.configure(function () { app.use(express.bodyParser()); app.use(express.methodOverride() ); app.use(app.router); app.use(express.static(path.join(application_root, "public"))); //app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); app.use(errorHandler); }); function errorHandler(err, req, res, next) { // 做的事情 return res.send(JSON.stringify(errorInfo, null, 2), errorInfo.code); };
    • @Prem 究竟是什么不起作用?根本没有调用错误处理程序吗?另外,errorInfo.code 到底是什么?它应该是一个数字。
    • 是的。当 api 调用遇到错误时,express error-handler 不返回响应并且应用程序捕获未捕获的异常。
    • @Prem 如果错误处理程序本身发生任何异常,那显然是一件坏事:) 所以你必须确保问题不是在那里引起的。
    • 似乎错误处理程序没有错误。我需要将 app.use(express.errorHandler) 放在 api 调用下面吗?
    猜你喜欢
    • 1970-01-01
    • 2019-11-08
    • 1970-01-01
    • 2012-01-18
    • 2016-06-16
    • 2020-05-13
    • 2019-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多