DEBUG.WIKI
阿里云;从建站到云上业务;云服务器 · 数据库 · 对象存储;查看产品 →
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →

Fastify 自定义正文解析器抛错,为什么没进错误处理器

Fastify 5.12.7 自定义 callback 正文解析器的同步 throw 可能逃出请求错误路径。局部捕获并只调用一次 done,保留原解析安全、正文限制和错误状态映射。

自定义正文解析器遇到坏输入直接 throw,Fastify 的 setErrorHandler 却没有接到它,进程反而出现 uncaughtException。如果使用 Fastify 5.12.7 的 callback 解析器,应把解析错误通过 done 返回,不要依赖路由处理函数的异常捕获来覆盖这段调用。

5.12.7 在流式入口与 parseAs 收集完正文后的入口,都直接调用 parser.fn;返回 Promise 时会接收拒绝,但同步 throw 没有相同的局部捕获。默认 JSON 解析器自己有捕获逻辑,不表示自定义解析函数也自动拥有它。

让解析结果与解析错误各返回一次

下面展示已有自定义 JSON 解析逻辑的接线方式。parseReport 应沿用项目原来的安全解析与输入约束,不在这里替换成没有相同保护的 JSON.parse:

app.addContentTypeParser(
  'application/x-report+json',
  { parseAs: 'string' },
  (request, body, done) => {
    let value;
    try {
      value = parseReport(body);
    } catch (error) {
      return done(error);
    }
    done(null, value);
  },
);

这是已有 app 在启动前注册的片段,媒体类型应与接口真实约定相符,parseReport 由应用提供。try 只包住解析步骤,避免把 done 后续处理中的错误再次当成解析错误回传,造成重复完成。

如果解析器已采用 async,则保留 Promise 返回风格,让错误以拒绝传回;不要同时声明 async 又调用 done。两种完成机制混用,可能引入另一种重复处理。

坏输入与程序错误不能统一标成一种状态

只有已经确认是请求格式或校验失败的错误,才应按原接口映射为合法的 4xx。未知内部错误仍走原来的 5xx 处理,不能为了避免进程退出,把所有异常都设成 400,或在 catch 中返回空对象伪装解析成功。

保留原来的 bodyLimit、认证、媒体类型、原型污染处理与字段校验。自定义解析器若替代了默认 JSON 行为,还需明确承担默认解析器原本提供的安全规则,不能只补 try/catch 后就认为两者等价。

流模式还涉及流错误、结束和资源收尾;上述 string 示例利用 Fastify 收集正文,不应原样套到任意流式 parser 中。全局 uncaughtException 监听器也不是单次请求的解析错误处理器,不能捕获后继续当作服务器已经正常回复。

截至 2026 年 10 月 26 日,正式 5.12.7 仍有上述直接调用路径,不能把一个尚未进入正式包的捕获改动当成已安装修复。验收覆盖正常正文、坏格式、空输入、超限正文与内部异常,检查客户端错误响应、后续请求及进程状态,而不只是观察一条日志。