跳至主内容
版本:11.x

错误处理

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

当某个过程中发生错误时,tRPC 会向客户端返回包含 "error" 属性的响应对象。该属性包含你在客户端处理错误所需的全部信息。

以下是由无效请求输入导致的错误响应示例:

json
{
"id": null,
"error": {
"message": "\"password\" must be at least 4 characters",
"code": -32600,
"data": {
"code": "BAD_REQUEST",
"httpStatus": 400,
"stack": "...",
"path": "user.changepassword"
}
}
}
json
{
"id": null,
"error": {
"message": "\"password\" must be at least 4 characters",
"code": -32600,
"data": {
"code": "BAD_REQUEST",
"httpStatus": 400,
"stack": "...",
"path": "user.changepassword"
}
}
}

生产环境中的堆栈跟踪

默认情况下,tRPC 仅在 isDevtrue 时包含 error.data.stackinitTRPC.create() 默认将 isDev 设置为 process.env.NODE_ENV !== 'production'。 如需在不同运行时环境下保持确定性行为,请手动覆盖 isDev 的值。

server.ts
ts
import { initTRPC } from '@trpc/server';
 
const t = initTRPC.create({ isDev: false });
server.ts
ts
import { initTRPC } from '@trpc/server';
 
const t = initTRPC.create({ isDev: false });

如需更严格地控制返回的错误字段,请使用错误格式化

错误代码

tRPC 定义了一组错误代码,每个代码代表不同类型的错误,并对应不同的 HTTP 状态码。

CodeDescriptionHTTP code
PARSE_ERRORInvalid JSON was received by the server, or an error occurred while parsing the request.400
BAD_REQUESTThe server cannot or will not process the request due to something that is perceived to be a client error.400
UNAUTHORIZEDThe client request has not been completed because it lacks valid authentication credentials for the requested resource.401
PAYMENT_REQUIREDThe client request requires payment to access the requested resource.402
FORBIDDENThe client is not authorized to access the requested resource.403
NOT_FOUNDThe server cannot find the requested resource.404
METHOD_NOT_SUPPORTEDThe server knows the request method, but the target resource doesn't support this method.405
TIMEOUTThe server would like to shut down this unused connection.408
CONFLICTThe request conflicts with the current state of the target resource.409
PRECONDITION_FAILEDAccess to the target resource has been denied.412
PAYLOAD_TOO_LARGERequest entity is larger than limits defined by server.413
UNSUPPORTED_MEDIA_TYPEThe server refuses to accept the request because the payload format is in an unsupported format.415
UNPROCESSABLE_CONTENTThe server understands the request method, and the request entity is correct, but the server was unable to process it.422
PRECONDITION_REQUIREDThe server cannot process the request because a required precondition header (such as If-Match) is missing. When a precondition header does not match the server-side state, the response should be 412 Precondition Failed.428
TOO_MANY_REQUESTSThe rate limit has been exceeded or too many requests are being sent to the server.429
CLIENT_CLOSED_REQUESTThe client closed the connection before the server finished responding.499
INTERNAL_SERVER_ERRORAn unspecified error occurred.500
NOT_IMPLEMENTEDThe server does not support the functionality required to fulfill the request.501
BAD_GATEWAYThe server received an invalid response from the upstream server.502
SERVICE_UNAVAILABLEThe server is not ready to handle the request.503
GATEWAY_TIMEOUTThe server did not get a response in time from the upstream server that it needed in order to complete the request.504

tRPC 提供了辅助函数 getHTTPStatusCodeFromError,用于从错误中提取 HTTP 状态码:

ts
import { getHTTPStatusCodeFromError } from '@trpc/server/http';
 
// Example error you might get if your input validation fails
const error: TRPCError = {
name: 'TRPCError',
code: 'BAD_REQUEST',
message: '"password" must be at least 4 characters',
};
 
if (error instanceof TRPCError) {
const httpCode = getHTTPStatusCodeFromError(error);
console.log(httpCode); // 400
}
ts
import { getHTTPStatusCodeFromError } from '@trpc/server/http';
 
// Example error you might get if your input validation fails
const error: TRPCError = {
name: 'TRPCError',
code: 'BAD_REQUEST',
message: '"password" must be at least 4 characters',
};
 
if (error instanceof TRPCError) {
const httpCode = getHTTPStatusCodeFromError(error);
console.log(httpCode); // 400
}
技巧

关于服务端上下文中的错误处理完整示例,请参阅服务端调用文档

抛出错误

tRPC 提供了 TRPCError 错误子类,用于表示在过程中发生的错误。

例如,抛出以下错误:

server.ts
ts
import { initTRPC, TRPCError } from '@trpc/server';
 
const t = initTRPC.create();
 
const theError = new Error('something went wrong');
 
const appRouter = t.router({
hello: t.procedure.query(() => {
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'An unexpected error occurred, please try again later.',
// optional: pass the original error to retain stack trace
cause: theError,
});
}),
});
 
// [...]
server.ts
ts
import { initTRPC, TRPCError } from '@trpc/server';
 
const t = initTRPC.create();
 
const theError = new Error('something went wrong');
 
const appRouter = t.router({
hello: t.procedure.query(() => {
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'An unexpected error occurred, please try again later.',
// optional: pass the original error to retain stack trace
cause: theError,
});
}),
});
 
// [...]

将生成以下响应:

json
{
"id": null,
"error": {
"message": "An unexpected error occurred, please try again later.",
"code": -32603,
"data": {
"code": "INTERNAL_SERVER_ERROR",
"httpStatus": 500,
"stack": "...",
"path": "hello"
}
}
}
json
{
"id": null,
"error": {
"message": "An unexpected error occurred, please try again later.",
"code": -32603,
"data": {
"code": "INTERNAL_SERVER_ERROR",
"httpStatus": 500,
"stack": "...",
"path": "hello"
}
}
}

错误处理

过程中发生的所有错误都会先经过 onError 方法处理,再发送给客户端。您可以在此处处理错误(修改错误格式请参阅错误格式化)。

server.ts
ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { appRouter } from './router';
 
const server = createHTTPServer({
router: appRouter,
onError(opts) {
const { error, type, path, input, ctx, req } = opts;
console.error('Error:', error);
if (error.code === 'INTERNAL_SERVER_ERROR') {
// send to bug reporting
}
},
});
server.ts
ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { appRouter } from './router';
 
const server = createHTTPServer({
router: appRouter,
onError(opts) {
const { error, type, path, input, ctx, req } = opts;
console.error('Error:', error);
if (error.code === 'INTERNAL_SERVER_ERROR') {
// send to bug reporting
}
},
});

onError 参数是一个包含错误本身及其上下文所有信息的对象:

ts
interface OnErrorOpts {
error: TRPCError;
type: 'query' | 'mutation' | 'subscription' | 'unknown';
path: string | undefined;
input: unknown;
ctx: unknown;
req: Request;
}
ts
interface OnErrorOpts {
error: TRPCError;
type: 'query' | 'mutation' | 'subscription' | 'unknown';
path: string | undefined;
input: unknown;
ctx: unknown;
req: Request;
}