Twirp 是基于 HTTP/1.1 的轻量级 RPC 框架,用 JSON/Protobuf 通信,不依赖 HTTP/2 和 gRPC 生态;适合浏览器、curl 等客户端及受限代理环境,调试简单但不支持流式调用。

Twirp 和 gRPC 在 Go 里到底差在哪
Twirp 不是 gRPC 的“替代品”,而是另一条路:它用纯 HTTP/1.1 + JSON/Protobuf 通信,不依赖 HTTP/2 或 gRPC 生态的二进制协议栈。如果你的客户端是浏览器、curl、Postman,或者服务要跑在不支持 HTTP/2 的代理(比如某些老版本 Nginx、AWS ALB)后面,Twirp 往往更省事。
常见错误现象:rpc error: code = Unavailable desc = transport is closing —— 这类报错在 gRPC 里常因 HTTP/2 流控、TLS 握手失败或代理截断引起;Twirp 默认走 HTTP/1.1,反而更“钝感”,排查路径更直。
- gRPC 强绑定
grpc-go客户端和服务端,必须用grpc.Dial、grpc.NewServer - Twirp 只需要标准
http.ServeMux或任意 HTTP 路由器(如chi、gorilla/mux),服务端本质就是一堆http.HandlerFunc - Twirp 生成的客户端默认发
POST /twirp/{package}.{service}/{method},响应体是裸 Protobuf 或 JSON,没有 gRPC 的 frame header 和状态码映射逻辑
用 twirp-gen 替代 protoc-gen-go-grpc 的实操要点
Twirp 不用 protoc-gen-go-grpc,改用官方 twirp-gen 插件(Go 实现,无需额外安装 protoc 插件二进制)。它只生成 client 和 server 接口+HTTP 路由绑定代码,不碰底层传输。
使用场景:你已有 .proto 文件,想快速暴露为 HTTP API,且不希望引入 gRPC 的 context deadline 透传、流式调用等复杂语义。
立即学习“go语言免费学习笔记(深入)”;
- 安装:
go install github.com/twitchtv/twirp/v8/cmd/twirp-gen@latest - 生成命令:
twirp-gen --proto_path=. --twirp_out=. --go_out=. helloworld.proto(注意:不用--go-grpc_out) - 生成的
HelloworldServiceServer是个 interface,实现它即可;NewHelloworldServiceClient返回的是纯 HTTP client,底层用http.DefaultClient,可轻松替换 transport 或加 middleware - 参数差异:
twirp-gen默认开启 JSON 支持(Accept: application/json自动 fallback),而 gRPC 的grpc-gateway需额外配置和中间件
Twirp 的 HTTP 错误码和 gRPC 状态码怎么对齐
Twirp 把 gRPC status code 映射成 HTTP 状态码,但不是一一对应,比如 codes.NotFound → 404,codes.InvalidArgument → 400,但 codes.Unauthenticated 默认是 401,而 codes.PermissionDenied 是 403。这个映射写死在 twirp.Error 的 Code() 方法里,不可配置。
容易踩的坑:前端直接读 HTTP 状态码做判断,结果发现 codes.Internal 被转成 500,但业务上你希望区分“服务崩溃”和“下游超时”,这时得靠 response body 里的 twirpError.Code 字段(JSON 响应中叫 code),而不是只看 HTTP status。
- Twirp 错误响应体始终包含
code(字符串)、msg、meta字段,无论 Content-Type 是application/protobuf还是application/json - 不要在 Twirp handler 里手动写
w.WriteHeader(400),应该返回&twirp.Error{Code: twirp.InvalidArgument, Msg: "..."},由框架统一处理 - 兼容性影响:gRPC-Web 客户端无法直连 Twirp 服务,因为协议不同;但 Axios/Fetch 可以,只要设置正确的
Content-Type和路径
什么时候该坚持用 gRPC,而不是切 Twirp
如果项目已重度依赖 gRPC 流式接口(server-streaming/client-streaming/bidi)、连接多路复用、或需要和 Java/Python 的 gRPC 生态(如 Envoy xDS、gRPC Health Checking)深度集成,强行切 Twirp 反而增加维护成本。
性能影响:Twirp 在小 payload 下比 gRPC 略慢(HTTP/1.1 没有 stream 复用,每个 RPC 单独 TCP 连接或短连接),但差距通常在毫秒级;真正卡点往往是序列化(JSON vs Protobuf)和 TLS 开销,而非框架本身。
- Twirp 不支持流式 RPC,所有方法必须是 unary(一问一答)
- gRPC 的
Keepalive、MaxConcurrentStreams、Per-RPC Creds等高级特性,Twirp 没有等价物 - 调试难度:Twirp 请求能被
curl -v完整看到,gRPC 调试必须用grpcurl或 Wireshark 解析 HTTP/2
真正复杂的不是选型,是混合部署时的网关策略——比如同一个服务同时暴露 Twirp JSON 端点给前端、gRPC 端点给内部服务,这时候 path prefix 冲突、CORS、鉴权透传才是实际要花时间啃的地方。










