Skip to Content
🎉 gRPCity 3.0 is released. Read more →

Error

gRPCity 把所有失败都以可识别的错误形式抛给客户端,你可以精确地 catch。 无论失败源于 handler、网络、deadline 还是 AbortSignal,错误的形态都能 告诉你究竟发生了什么。

GrpcClientError 字段

当 unary 调用 reject、或 stream 在 for await 上抛出,客户端会收到一个 GrpcClientError,包含以下字段:

字段说明
name永远是 'GrpcClientError'。用它区分框架错误和普通错误。
codegRPC status code 数字。1CANCELLED4DEADLINE_EXCEEDED
details服务端返回的 status 字符串(若有)。
metadata失败时携带的 trailing metadata。
message组合后的错误消息,包含方法路径和服务端 stack(方便日志使用)。
stack抛错处的客户端调用栈。

例子:

try { await client.sayGreet({ name: 'gRPCity' }) } catch (err) { if (err.name === 'GrpcClientError') { if (err.code === 1) { // CANCELLED — 通常由 AbortSignal 或 call.cancel() 触发 } else if (err.code === 4) { // DEADLINE_EXCEEDED — 需要调大 timeout 或降流量 } else { // 其他非 OK 状态 } } else { throw err } }

AbortErrorGrpcClientError 的区分

当传入的 AbortSignal 在 RPC 还进入网络层之前就触发,gRPCity 会 同步 reject signal 的 reason(一个标准的 AbortErrorcode: 20), 完全不发起调用。如果是调用进行中触发,gRPCity 会把 abort 翻译为底层 的 call.cancel(),错误形态是 GrpcClientErrorcode: 1

详见 AbortSignal

流式 RPC

GrpcClientError 形态同样适用于流式 RPC。错误会通过 for await 抛出:

const call = await client.serverStreamHello({ message: 'x' }) try { for await (const data of call.readAll()) { // ... } } catch (err) { // err.name === 'GrpcClientError',err.code 是 gRPC status }

Client stream 与 bidi 的失败同样从 await call.writeEnd()for await ... call.readAll() 抛出。

服务端触发错误

直接 throw 即可。gRPCity 会把抛出的 Error 转换成 wire 上的 gRPC status;四种 RPC handler(unary、client stream、server stream、bidi)都 保证 throw 会以 GrpcClientError 形态到达客户端。

async sayHello(call) { const metadata = call.metadata.clone() metadata.add('x-timestamp-server', 'received=' + new Date().toISOString()) call.sendMetadata(metadata) if (metadata.get('x-throw-error').length > 0) { throw new Error('throw error because x-throw-error') } return { message: `hello, ${call.request.name || 'world'}` } }

对于 server-stream / bidi handler,throw 就是正确的失败方式 —— gRPCity 会通过底层 server stream 的 'error' 通道发回 status trailer, 让客户端立刻收到错误,而不是等到 deadline 才超时。

Last updated on