如何在tRPC中间件中捕获tRPC过程抛出的Google API相关错误?
如何在tRPC中间件层统一捕获并处理Google API错误
我正在开发一个集成Google Drive和Spreadsheet APIs的tRPC应用,为此实现了自定义googleProcedure中间件,向查询或变更操作注入必要上下文,以便基于已认证用户访问Drive文件或表格。我的目标是简化错误处理,拦截来自Google API相关查询或过程的错误,避免在每个单独过程中重复编写错误捕获代码。但当前实现无法有效捕获过程中的错误,代码片段如下:
const googleProcedure = protectedProcedure.use(async ({ ctx, next }) => { // Initialization of googleClient, sheets, and drive try { return await next({ ctx: { ...ctx, sheets, drive, }, }); } catch (err) { if (err && err instanceof GaxiosError && err.code == '401') { throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Not authenticated with Google', }); } throw err; } }); // Definitions for googleSpreadsheet router... export const spreadsheet = router({ create: googleProcedure.mutation(async ({ ctx, input }) => {}), appendRow: googleProcedure.mutation(async ({ ctx, input }) => {}), getAll: googleProcedure.query(async ({ ctx, input }) => {}), trash: googleProcedure.mutation(async ({ ctx, input }) => {}), });
我尝试捕获Google相关的401错误并重新抛出为带有UNAUTHORIZED代码的TRPCError,但该方法未能按预期捕获错误。
问题分析
当前实现失效的常见原因有两个:
- GaxiosError类型判断失效:未正确导入
GaxiosError,导致instanceof判断不成立,错误无法被识别。 - 错误码类型不匹配:Google API返回的
GaxiosError中,err.code可能是数字形式的HTTP状态码(如401),而非字符串'401',导致判断条件不触发。
修正后的实现
以下是调整后的中间件代码,确保能正确捕获并处理Google API错误:
import { GaxiosError } from 'gaxios'; import { TRPCError } from '@trpc/server'; const googleProcedure = protectedProcedure.use(async ({ ctx, next }) => { let sheets, drive; try { // 初始化Google客户端及API实例(将初始化逻辑也纳入错误捕获) const googleClient = await getAuthenticatedGoogleClient(ctx.user.id); sheets = googleClient.sheets({ version: 'v4' }); drive = googleClient.drive({ version: 'v3' }); // 执行后续过程并注入上下文 return await next({ ctx: { ...ctx, sheets, drive, }, }); } catch (err) { // 优先判断是否为Google API的GaxiosError if (err instanceof GaxiosError) { const statusCode = err.response?.status || err.code; // 兼容数字和字符串形式的状态码 if (statusCode === 401 || statusCode === '401') { throw new TRPCError({ code: 'UNAUTHORIZED', message: '未通过Google身份验证', }); } // 可扩展处理其他常见Google API错误 if (statusCode === 403 || statusCode === '403') { throw new TRPCError({ code: 'FORBIDDEN', message: '没有访问该Google资源的权限', }); } } // 非Google API错误,原样抛出 throw err; } }); // 路由定义无需修改,过程内无需额外try-catch export const spreadsheet = router({ create: googleProcedure.mutation(async ({ ctx, input }) => { await ctx.sheets.spreadsheets.create({ /* 参数 */ }); }), appendRow: googleProcedure.mutation(async ({ ctx, input }) => { await ctx.sheets.spreadsheets.values.append({ /* 参数 */ }); }), getAll: googleProcedure.query(async ({ ctx, input }) => { return await ctx.sheets.spreadsheets.values.get({ /* 参数 */ }); }), trash: googleProcedure.mutation(async ({ ctx, input }) => { await ctx.drive.files.update({ /* 参数 */ }); }), });
关键优化点
- 正确导入GaxiosError:确保从
gaxios或googleapis包中导入GaxiosError,保证类型判断有效。 - 兼容状态码类型:同时判断数字和字符串形式的状态码,覆盖Google API返回的不同格式。
- 包含初始化逻辑的错误捕获:将Google客户端的初始化过程也纳入try-catch,捕获认证阶段的错误。
- 扩展错误处理能力:可根据需求添加更多Google API常见错误的处理逻辑(如404资源不存在、429请求限流等)。
内容的提问来源于stack exchange,提问作者Anatol Zakrividoroga
相关产品推荐
相关产品推荐

