You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fastify中不使用async/await或.catch时如何处理UnhandledPromiseRejectionWarning

Fastify 捕获未处理异步错误触发全局错误处理方案

问题根因

你当前代码不生效的核心原因是Fastify的setErrorHandler默认仅能捕获两类错误:

  • 路由处理函数同步执行时抛出的异常
  • 路由处理函数返回的Promise被reject时抛出的异常

你代码里的fetch返回的Promise没有被return到路由处理函数外层,也没有绑定catch处理,属于游离的未托管Promise,Fastify的错误处理链感知不到这部分异常,所以会触发Node.js全局的UnhandledPromiseRejectionWarning,同时请求因为一直未调用response.send会超时挂起。

解决方案

方案1:统一封装请求库(符合你允许修改请求库的前提)

通过Fastify钩子给每个请求上下文注入封装后的请求方法,内部自动兜底错误,无需开发者手动加catch:

import fastify from 'fastify';
import originalFetch from 'node-fetch';

const app = fastify();

app.setErrorHandler(async (error, request, response) => {
    console.log('setErrorHandler');
    response.status(500).send('error');
});

// 全局注入封装后的fetch
app.addHook('onRequest', (request, reply, done) => {
  request.fetch = (url, options) => {
    return originalFetch(url, options)
      .then(res => res)
      .catch(err => {
        // 错误自动触发全局错误处理
        if (!reply.sent) reply.send(err)
        throw err
      })
  }
  done()
})

// 开发者无需修改原有写法,仅需要调用上下文中的fetch即可
app.get('/', (request, response) => {
    request.fetch('https://...').then(() =>  { response.send(); });
});

方案2:全局兜底未处理的Promise rejection(无需修改开发者业务代码)

如果无法约束开发者统一使用封装后的请求库,可以结合Node.js的AsyncLocalStorage跟踪请求上下文,全局捕获所有未处理的异步错误,自动关联到对应请求触发错误返回:

import fastify from 'fastify';
import fetch from 'node-fetch';
import { AsyncLocalStorage } from 'async_hooks'

const app = fastify();
const asyncStorage = new AsyncLocalStorage()

app.setErrorHandler(async (error, request, response) => {
    console.log('setErrorHandler');
    response.status(500).send('error');
});

// 请求进入时存入异步上下文
app.addHook('onRequest', (request, reply, done) => {
  asyncStorage.run({ request, reply }, done)
})

// 全局监听未处理的Promise rejection
process.on('unhandledRejection', (reason) => {
  const store = asyncStorage.getStore()
  // 仅处理未返回响应的当前请求关联的错误
  if (store && store.reply && !store.reply.sent) {
    store.reply.send(reason)
    return
  }
  // 非请求关联的错误正常兜底打日志
  console.error('全局未处理Promise rejection:', reason)
})

// 开发者的业务代码不需要做任何修改
app.get('/', (request, response) => {
    fetch('https://...').then(() =>  { response.send(); });
});

该方案完全不需要修改开发者编写的接口处理逻辑,无论开发者是否忘记加catch、是否使用async/await,都能自动捕获错误触发全局错误处理,返回500状态码。


内容的提问来源于stack exchange,提问作者Rodrigo Ruiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.08 07:21:01