接口设计基础:RESTful 与 gRPC 设计规范

讲讲接口设计吧。金融场景里,接口就是数据的门。门设计得不好,数据就乱跑,或者干脆进不来。我经历过不少项目,接口设计这块坑很多,今天我把 RESTful 和 gRPC 这两套东西掰开揉碎讲清楚。

RESTful 接口设计规范

RESTful 说白了就是「用 HTTP 协议定义资源操作」。资源用 URL 表示,操作用 HTTP 方法表示。就这么简单。但金融场景里得注意几个关键点。

资源路径设计

资源路径要名词复数,动词靠 HTTP 方法覆盖。我见过很多团队在 URL 里塞动词,比如 /api/getUserInfo,乱得不行。

正确示例:

GET    /api/privacy/v2/users/{userId}
POST   /api/privacy/v2/users/{userId}/consents
PUT    /api/privacy/v2/users/{userId}/consents/{consentId}
DELETE /api/privacy/v2/users/{userId}/consents/{consentId}

错误示例:

GET  /api/getUserInfo?userId=123
POST /api/saveConsent
PUT  /api/updateConsentInformation

注意版本号 v2 放在路径里。金融系统迭代慢但必须向前兼容,路径版控最稳。我在银行项目里吃过没版本号的亏,后来不得不做网关重写。

HTTP 方法选择与幂等性

这个很重要。金融场景的接口必须讲清楚幂等性。我做个表给你们看看:

HTTP 方法 语义 幂等 金融场景示例
GET 查询资源 是 查询用户隐私授权状态
POST 创建资源 否 提交隐私授权申请
PUT 全量替换 是 更新用户隐私偏好设置
PATCH 部分更新 否 更新用户某个同意项
DELETE 删除资源 是 撤销某项隐私授权

幂等性不是小事。我曾经遇到过一个扣费服务因为超时重试导致重复扣款,就是因为 POST 不幂等。后来加了一个请求唯一 ID 方案才解决。

数据校验与请求格式

金融接口的数据校验要严格。我一般会在网关层和业务层各做一次校验。请求体用 JSON,但日期、金额这些字段要规定好格式:

  • 日期:统一用 ISO 8601,比如 2024-12-01T10:30:00+08:00
  • 金额:用整数表示最小单位(分),或者用 decimal 字符串
  • 敏感字段:请求体里不要出现明文身份证号、卡号

注意:金融场景不要用 application/x-www-form-urlencoded 提交隐私数据。JSON 结构化丢给后端,签名和加密由网关统一处理。

gRPC 接口设计规范

RESTful 在对外暴露接口时很有用。但内部服务之间通信,我更喜欢 gRPC。为什么?性能好,强类型,天然支持流式通信。

.proto 文件就是接口契约

gRPC 的接口定义在 .proto 文件里。这文件既是规范,也是文档,还能自动生成代码。金融场景里,接口一致性是命根子,protobuf 的严格模式恰好满足这一点。

syntax = "proto3";

package privacy.v2;

message QueryConsentRequest {
  string user_id = 1;
  string request_id = 2; // 幂等用
}

message QueryConsentResponse {
  string user_id = 1;
  repeated ConsentItem consents = 2;
  string timestamp = 3; // ISO 8601
}

message ConsentItem {
  string consent_id = 1;
  string consent_type = 2; // e.g., "data_share", "marketing"
  bool granted = 3;
  int64 expire_at = 4; // unix timestamp
}

service PrivacyService {
  rpc QueryConsent (QueryConsentRequest) returns (QueryConsentResponse);
  rpc UpdateConsent (stream ConsentUpdateRequest) returns (AckResponse);
}

字段编号别乱用。我用 1-15 放高频字段,因为编码后只占 1 字节。16-2047 放低频字段。这是我踩过的坑,一开始没规划,后来改字段编译出来的二进制大了一截。

服务定义与通信模式

gRPC 支持四种模式。金融场景里我常用的有两种:

通信模式 描述 金融场景
Unary RPC 一问一答 查询隐私授权状态
Server Streaming 客户端发送一个请求,服务端持续返回流式数据 批量导出隐私日志
Client Streaming 客户端持续发送数据,服务端统一响应 批量更新个人信息
Bidirectional Streaming 双向实时通信 实时隐私风险检测

经验之谈:内部服务用 gRPC 时,把超时控制在 5 秒内。金融系统对延迟敏感,gRPC 流式通信如果网络抖动,容易造成批量数据丢失。我在一个日志导出项目里因为没设超时,导致连接一直挂着。

数据格式:JSON vs Protocol Buffers vs FlatBuffers

接口设计绕不开数据格式。我总结了一下三种格式的特点:

格式 序列化速度 数据大小 可读性 适用场景
JSON 慢 大 好 对外开放接口、调试
Protocol Buffers 快 小 差 内部服务调用、高吞吐
FlatBuffers 极快 小 差 高频交易、移动端

为什么会这样?JSON 是文本协议,解析时要建对象树,天生慢。Protocol Buffers 是二进制协议,直接映射结构体。FlatBuffers 连反序列化都省了,直接访问内存。金融场景里,对外接口我坚持用 JSON,调试方便。内部高并发服务,用 Protocol Buffers。实时高频交易,FlatBuffers 是首选。

状态码归纳总结

状态码是接口的「说话方式」。设计不好,调用方猜都猜不到发生了什么。

RESTful 状态码选择

我的经验是不要滥用 200 和 500。很多团队不管结果怎么样都返回 200,然后在 body 里放 code: 10001 表示错误。这样 API 网关做熔断和统计就废了。

HTTP 状态码 含义 金融场景使用时机
200 OK 正常处理完成 查询成功、更新成功
201 Created 资源创建成功 新建隐私授权记录
400 Bad Request 请求参数错误 请求缺少 user_id、签名无效
401 Unauthorized 身份认证失败 令牌过期、无权限调用
403 Forbidden 无操作权限 用户非本人、数据不可达
404 Not Found 资源不存在 请求的 user_id 或 consent_id 不存在
409 Conflict 资源冲突 请求幂等 ID 重复
429 Too Many Requests 频率限制 单位时间内请求数超限
500 Internal Server Error 服务端内部错误 数据库异常、配置错误
503 Service Unavailable 服务暂时不可用 网关限流、熔断

注意:金融接口里 409 特别重要。幂等机制依赖唯一 ID,如果重复请求来了,别返回 200,返回 409 让调用方自己判断。我曾经见过返回 200 导致下游重复处理业务,差点损失几百万。

gRPC 状态码与 HTTP 映射

gRPC 有自己的一套状态码。通过 gRPC-gateway 转 REST 时,映射关系要提前约定好。

gRPC 状态码 HTTP 状态码 说明
OK (0) 200 正常
InvalidArgument (3) 400 请求参数校验失败
Unauthenticated (16) 401 认证失败
PermissionDenied (7) 403 权限不足
NotFound (5) 404 资源不存在
AlreadyExists (6) 409 资源已存在,幂等冲突
ResourceExhausted (8) 429 限流触发
Internal (13) 500 内部错误
Unavailable (14) 503 服务不可用

gRPC 状态码返回时,建议在 trailers 里附带更多错误信息。我习惯在业务错误时额外返回一个 error_details 字段,方便排查问题。

个人习惯:无论用 RESTful 还是 gRPC,我都统一封装一个响应结构。REST 用 { "code": 200, "message": "success", "data": {...} },gRPC 用 error_details.message。这样前端和调用方不用猜状态码的私有含义。

核心知识体系图

下面这张图概括了这一章的核心内容。把 RESTful 和 gRPC 的设计规范、数据格式选择、状态码映射放在一起,你们可以当个快速参考。

接口设计核心知识体系 RESTful 接口设计 gRPC 接口设计 资源路径设计 HTTP 方法选择 数据校验与格式 .proto 契约 通信模式 流式处理 数据格式选择 JSON Protocol Buffers FlatBuffers 状态码体系 HTTP 状态码(REST) gRPC 状态码 幂等性 + 安全校验是基石

接口设计说复杂也复杂,说简单也简单。RESTful 对外,gRPC 对内,数据格式按场景选,状态码按规范走。这套框架用好了,金融系统的接口会非常清晰。记住我说的:接口是门,设计好它,数据才安全。