javascript - 在 NodeJS 中处理发布请求失败的正确方法是什么?

标签 javascript node.js

我的 previous question写得真的很糟糕(对此感到抱歉!)所以这次我会尽量把它做好。我正在使用 NodeJS 并编写了以下代码:

const car_reporter = {
    // Some Code here (Removed to make it clear)

    httpClient : null,

    scriptReport:  function(username, options) { // Some code here (Removed to make it clear)
    },

    APIReport: function(username, options) {
        if (!(this.httpClient)) {
            this.init();
        }
        try {
            if ('car' in options) {
                var reqConfig = {
                    method: 'post',
                    url: '/car',
                    headers: {
                        'content-type': 'application/json',
                    },
                    data: {
                        'carName': carName, // global
                        'username': username,
                        'car': options.car
                    }
                };
                this.httpClient(reqConfig).catch(function (error) {
                    throw new Error('Error while posting car\n' + error);
                });
            }
            // OTHER CODE HERE - NOTICE ME :) (Removed to make it clear)
        } catch (e) {
            return e;
        }
    },

    report: function (username, options) {
        if (username === null) {
            return new Error('Invalid username');
        }
        if (fs.existsSync(this.script_path)) {
            return this.scriptReport(username, options);
        } else {
            return this.APIReport(username, options);
        }
    },

    init: function() {
        this.httpClient = axios.create({
            baseURL: this.api_url
        });
    }
};

module.exports = car_reporter;

我这样调用它:

function report_car(user_id, car) {
    var options = { car: car };
    var result = car_reporter.report(user_id, options);
    if (result instanceof Error) {
        logger.error(result);
    }
}

如果发布失败,我想在 APIReport 中抛出 Error。但它说:UnhandledPromiseRejectionWarning: Unhandled promise rejection。如果发布请求不起作用,这里处理错误并返回 Error 的正确方法是什么?我不能做 return this.httpClient(... 因为在那个请求之后还有其他代码。我可能需要添加 .then(... 但我该怎么做知道发帖失败了吗?

最佳答案

编辑

本版为评论提问。

如果你不想等待,你可以只删除 await 关键字,但是你不会收到 car_reporter.report 抛出的任何错误消息。

async function report_car(user_id, car) {
    var options = { car: car };
    try {
        car_reporter.report(user_id, options);
    } catch (error) {
        logger.error(error);
    }
}

你可以试试这个例子。
您将收到 UnhandledPromiseRejectionWarning 错误。
而你的 catch block 将不会被执行。

function test () {
    return new Promise((res, rej) => setTimeout(() => {
        rej("not good")
    }, 2000))
}

async function main() {
    try {
        test()
    } catch (error) {
        console.log("Get error");
        console.log(error);
    }
}

main()

在这种情况下,您可以在test() 后面添加.catch

function test () {
    return new Promise((res, rej) => setTimeout(() => {
        rej("not good")
    }, 2000))
}

async function main() {
    try {
        test().catch((error) => {
            console.log("Get error inside");
            console.log(error)
        })
    } catch (error) {
        console.log("Get error");
        console.log(error);
    }
    console.log("done");
}

main()

执行上面的代码后,你会发现首先打印的是done。然后 Get error inside 第二个被打印出来。我们假设您将在 console.log("done") 之后显示一些消息,但您不知道 test() 是否执行成功。 所以基本上,您不能在第一次执行时不等待就显示消息。

除非,您可以先向用户显示“正在处理”之类的消息。然后,告诉您的用户此 test() 是否成功。

回到你的代码。当您删除 await 时,您的 catch block 将无法正常工作。因此,您需要在 car_reporter.report 后面添加 .catch。 然后在 catch block 中处理错误消息。您可以发送电子邮件告诉您的用户此报告已损坏。但是,我不确定这个程序在哪里运行。如果用express as api服务运行,轮询也是一种方法。

async function report_car(user_id, car) {
    var options = {car: car};
    try {
        car_reporter.report(user_id, options).then((result) => {
            // send email with this successful result
            // tell your user this report is fine.
        }).catch((error) => {
            // send email with this error message
            // tell your user this report is broken.
        });
    } catch (error) {
        logger.error(error);
    }
    // told your user report is still processing.
}

原始答案

我根据你的修改代码。
因为你在这里使用的是 axios,所以我将使用 async-await 来重构代码。

我将首先使用 async-await 来重构 report_car 函数中的用法。

async function report_car(user_id, car) {
    var options = { car: car };
    var result = await car_reporter.report(user_id, options);
    if (result instanceof Error) {
        logger.error(result);
    }
}

然后我需要添加 try-catch 来避免 UnhandledPromiseRejectionWarning
car_reporter.report 中的任何抛出错误都将在 catch block 中。

async function report_car(user_id, car) {
    var options = { car: car };
    try {
        var result = await car_reporter.report(user_id, options);
    } catch (error) {
        logger.error(error);
    }
}

接下来,如果username为null,则会出现错误信息。
把它改成throw而不是return,因为外面用了async-await。
如果您使用 return,它将被视为一个 resolved promise。
因此,使用 throw 并使此错误发生在外部的 catch block 上。

report: function (username, options) {
    if (username === null) {
        throw new Error('Invalid username');
    }
    if (fs.existsSync(this.script_path)) {
        return this.scriptReport(username, options);
    } else {
        return this.APIReport(username, options);
    }
},

并且在处理错误时,您应该使用 throw 而不是 return
然后你会在 report_car 函数的 catch block 中得到错误。

APIReport: function (username, options) {
        if (!(this.httpClient)) {
            this.init();
        }
        try {
            if ('car' in options) {
                var reqConfig = {
                    method: 'post',
                    url: '/car',
                    headers: {
                        'content-type': 'application/json',
                    },
                    data: {
                        'carName': carName, // global
                        'username': username,
                        'car': options.car
                    }
                };
                const result = await this.httpClient(reqConfig)
                // handle something with result if you need it
                // other code here ...
            }
        } catch (e) {
            // you could custom error message here, and throw to outside
            // like `throw new Error("axios error")`
            console.log(e)
            throw new Error("axios error")
        }
    },

但是,如果上面例子中的这里的其他代码有错误,会发生什么。
也许你调用了一个不存在的函数,它会抛出未定义的错误。
你的 catch block 也会捕获它。
此时,您将抛出 new Error("axios error"),因为您自定义了错误消息。

那么,问题就来了。
如何区分这些错误或自定义?
您可以直接在您的 axios 中添加 catch,然后自定义错误消息,如以下代码。

APIReport: function (username, options) {
        if (!(this.httpClient)) {
            this.init();
        }
        try {
            if ('car' in options) {
                var reqConfig = {
                    method: 'post',
                    url: '/car',
                    headers: {
                        'content-type': 'application/json',
                    },
                    data: {
                        'carName': carName, // global
                        'username': username,
                        'car': options.car
                    }
                };
                const result = await this.httpClient(reqConfig).catch((error) => {
                    throw new Error("APIReport axios error")
                })
                // handle something with result if you need it
                // other code here ...
            }
        } catch (e) {
            // here, you could throw other customized error message
            // like, throw new Error("APIReport exception") 
            console.log(e)
            throw e;
        }
    },

但是,如果您在 axios catch block 中抛出错误,node 将不会执行我在 other code here 中提到的以下代码。

如果你想让代码在axios出错时继续执行,你应该在axios catch block 中使用return而不是throw
如果你不想让axios出错时代码不继续执行,你应该使用throw
这取决于您想要的情况。

整个代码如下所示。

const car_reporter = {
    httpClient: null,
    scriptReport: function (username, options) {},
    APIReport: function (username, options) {
        if (!(this.httpClient)) {
            this.init();
        }
        try {
            if ('car' in options) {
                var reqConfig = {
                    method: 'post',
                    url: '/car',
                    headers: {
                        'content-type': 'application/json',
                    },
                    data: {
                        'carName': carName, // global
                        'username': username,
                        'car': options.car
                    }
                };
                const result = await this.httpClient(reqConfig).catch((error) => {
                    throw new Error("APIReport axios error")
                })
                // handle something with result if you need it
                // other code here ...
            }
        } catch (e) {
            // here, you could throw other customized error message
            // like, throw new Error("APIReport exception") 
            console.log(e)
            throw e;
        }
    },

    report: function (username, options) {
        if (username === null) {
            throw new Error('Invalid username');
        }
        if (fs.existsSync(this.script_path)) {
            return this.scriptReport(username, options);
        } else {
            return this.APIReport(username, options);
        }
    },

    init: function () {
        this.httpClient = axios.create({
            baseURL: this.api_url
        });
    }
};

module.exports = car_reporter;
async function report_car(user_id, car) {
    var options = { car: car };
    try {
        var result = await car_reporter.report(user_id, options);
    } catch (error) {
        logger.error(error);
    }
}

希望对您有所帮助。

关于javascript - 在 NodeJS 中处理发布请求失败的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65200949/

相关文章:

javascript - 调用 Google map DirectionsService 时未捕获的异常

javascript - 当我从外部 api 获取数据时,如何将数据返回给客户端?

mysql - 如何覆盖日期的转义方式?

javascript - 从 MongoDB 驱动程序调用 getUsers() 函数

node.js - 我得到 - 错误 : Entry not found in cache - during sls deploy

javascript - 替换网页中无法访问的 javascript

javascript - 同位素过滤器和动画不起作用

javascript - 如何将 onclick 事件添加到 reactjs 中 dangerouslysetInnerHtml 呈现的字符串?

javascript - DIV 中的 OnClick 事件处理程序(第一个 OnClick 影响所有 DIV)

node.js - 如何更改 Bower 的默认组件文件夹?