async函数内try-catch无法捕获400错误的原因及写法差异
问题描述
开发Mailchimp API对接逻辑时,尝试在async异步函数内通过try-catch实现错误处理,始终无法捕获接口返回的400状态码请求错误,初始写法如下:
const run = async () => { const response = await client.lists.addListMember(listId, { email_address: email, status: "subscribed", merge_fields: { firstName: firstName, lastName: lastName } }); try { res.sendFile(__dirname + "/success.html"); } catch (err) { res.sendFile(__dirname + "/failure.html"); } }; run();
调整实现逻辑后,移除async函数内部的try-catch块,改为调用run异步函数时链式调用catch方法处理错误,该写法可正常捕获错误,调整后代码如下:
app.post("/", function(req, res) { const firstName = req.body.fname; const lastName = req.body.lname; const email = req.body.email; client.setConfig({ apiKey: "*****-us10", server: "us10", }); const listId = "****"; const run = async () => { const response = await client.lists.addListMember(listId, { email_address: email, status: "subscribed", merge_fields: { firstName: firstName, lastName: lastName } }); res.sendFile(__dirname + "/success.html"); }; run().catch(e => res.sendFile(__dirname + "/failure.html")); })
核心差异与失效原因
async/await的错误捕获遵循明确的作用域规则:只有被包裹在try块内部、且被await接收的异步操作抛出的异常,才会被同层级的catch块捕获。- 第一种写法无法捕获400错误的根本原因:会抛出400异常的
client.lists.addListMember请求操作,完全写在try块的外部。当接口返回400状态码时,Mailchimp SDK会立刻在await位置抛出异步异常,这个异常发生在try块代码执行之前,根本不会进入后续的try逻辑,自然无法被内部catch捕获。这段代码里的内部try块仅包裹了res.sendFile(success.html)这一句,它只能捕获成功页文件发送过程中抛出的错误,完全覆盖不到前面的API请求逻辑。 - 第二种写法可以正常捕获错误的原因:async函数调用后会返回一个Promise对象,函数内部任意位置抛出的异常(包括API请求的400错误、后续sendFile操作的错误),都会让这个Promise变为rejected状态,后续链式调用的
.catch()会捕获整个函数执行链路中的所有异常,因此可以正常拿到接口返回的400错误。
如果要在async函数内部用try-catch实现同等的错误捕获效果,只需要把所有可能抛错的逻辑都移入try块覆盖范围即可,参考写法:
const run = async () => { try { // 会抛错的API请求移入try块内 const response = await client.lists.addListMember(listId, { email_address: email, status: "subscribed", merge_fields: { firstName: firstName, lastName: lastName } }); res.sendFile(__dirname + "/success.html"); } catch (err) { // 此处可捕获API请求、文件发送全链路的错误 res.sendFile(__dirname + "/failure.html"); } }; run();
内容的提问来源于stack exchange,提问作者Jana
相关产品推荐
相关产品推荐

