Workers 验签错误已捕获,测试仍报 Unhandled Rejection
jose验签拒绝已处理、Vitest断言全过却多报运行时错误时,检查workerd兼容配置。启用微任务检查点后的拒绝处理,保留算法和签名限制,不全局忽略异步错误。
Workers 测试里的 JWT 校验已经被 await 和 catch 正确接住,所有断言也通过了,Vitest 最后却多报一条 Unhandled Rejection,导致进程非零退出。若错误是 JOSEAlgNotAllowed 或 ERR_JOSE_ALG_NOT_ALLOWED,先区分真正的验签拒绝与运行时额外上报。
一个明确组合是 jose 6.2.5、@cloudflare/vitest-pool-workers 0.19、Vitest 4.1.10,以及测试运行时仍采用 2025-06-01 的兼容日期。这里的算法拒绝本来就应发生;异常之处是测试已经消费了这个拒绝,workerd 仍提前发出了未处理拒绝事件。
测试全过,也可能在运行时错误阶段失败
旧兼容行为可能在一个微任务检查点尚未完成时,就判断 Promise 拒绝无人处理。多轮 Promise 链在后续微任务中补上处理器时,事件已经被过早上报。
jose 的内部 Promise 返回路径会暴露这种调度差异,但不能据此把 JWT 验证逻辑判为错误。把依赖内的 return 改成 return await 可能改变时序,却不是需要长期维护的修复入口。正式 jose 6.2.13 仍有直接返回验证 Promise 的实现,因此仅升级 jose 不一定改变测试运行时的上报时机。
只有真实验证错误已经被调用方处理、额外错误又符合该运行时条件时,才检查这条分支。应用中确实漏掉 await、脱离调用链启动任务,或 catch 本身再抛错,仍是真正的未处理拒绝。
在测试运行时启用微任务检查点后的处理
Cloudflare 提供 unhandled_rejection_after_microtask_checkpoint。它从兼容日期 2026-03-03 起默认启用,也可以在旧日期下单独启用。
如果项目的测试池使用显式 Miniflare 运行时选项,可在原配置中合并以下局部字段,保留其他设置:
{
compatibilityDate: '2025-06-01',
compatibilityFlags: [
'nodejs_compat',
'unhandled_rejection_after_microtask_checkpoint',
],
}
这是运行时选项片段,不是完整 Vitest 配置文件。若测试从 Wrangler 配置继承,则对应字段拼写为 compatibility_date 和 compatibility_flags;还须确认测试池没有用自己的选项覆盖它。不能只修改线上 Worker,而本机测试仍运行在另一份旧兼容配置下。
直接提高兼容日期也会启用期间其他行为变化,应按项目正常迁移流程评估。仅需隔离这条调度行为时,单独加入上述标志更容易比较;现有标志仍需保留,不用示例中的数组覆盖项目整份列表。
验签必须继续拒绝非法输入
用原来的失败令牌验证两件事:原有算法、签名和声明限制仍然拒绝不合法输入;测试运行时不再额外报告已处理的同一次拒绝。正常令牌的验证结果也应保持。
不要删除 algorithms 限制、放宽签名检查,或通过全局拦截 unhandledrejection 后忽略所有事件来让 CI 变绿。那会掩盖真正的异步错误,甚至改变认证边界。
该具体故障的受影响入口是测试运行时,不能据此宣称部署后的所有 Workers 都存在重复拒绝。若生产日志也有异常,应按实际兼容配置和调用链分别核对。测试的退出状态、原有认证断言以及运行时错误计数三项一致,才能确认这条误报分支已经恢复。


