常见问题
TcaplusDB PB表 RESTFul API 常见问题
1. restproxy响应消息中的http code用法
2.0 的响应映射看清楚了。接下来看 tcaprestproxy_http_msgproc.cpp 里的 93 处(包括请求入口、超时处理和 1.0 的响应处理),先列出每处所在的函数。
2.0 部分已经清楚。再看 1.0 的 ProcResponseFromTcaproxy,它的 500 用得多(55 处),要确认和 2.0 的差别在哪里。
1.0 的映射也清楚了。最后看一下 tcaproxyd 里的 10 处使用,判断要不要写进文档。
再补两处细节:2.0 请求阶段发送到 tcaproxy 失败时的返回值,以及超时配置项的名字。
下面是可以直接贴进文档的 restproxy HTTP 状态码说明,按当前代码里 6 个宏的全部用法整理(1.0 和 2.0 都覆盖)。最后附了梳理时发现的几处异常,其中第 1 条可能是鉴权漏洞,建议优先确认。
HTTP 状态码
restproxy 的所有响应体都是 JSON,都带 ErrorCode 和 ErrorMsg 两个字段,ErrorCode = 0 表示成功。
HTTP 状态码只用来区分错误大类,判断请求是否成功要看 ErrorCode:返回 200 时 ErrorCode 也可能不为 0。
| 状态码 | 含义 |
|---|---|
| 200 | 请求处理完成。ErrorCode = 0 表示成功;2.0 协议下有一部分错误也用 200 返回 |
| 400 | 请求在 restproxy 阶段被拒绝或处理失败;或存储层返回了和请求内容相关的错误 |
| 401 | 签名(密码 MD5)校验失败 |
| 404 | 记录或索引不存在 |
| 408 | 请求在 restproxy 中等待超时,或因为表结构变更、服务重新初始化被中止 |
| 500 | 存储层返回其他错误,或 restproxy 内部错误 |
200 OK
- 成功:
ErrorCode = 0,ErrorMsg = "Succeed"。 - 查询错误码描述(GetErrMsg):固定返回 200,
ErrorCode和ErrorMsg是被查询的错误码及其描述。 - 仅 2.0 协议:下面这些情况返回 200,但
ErrorCode不为 0。- 存储层返回成功,但 restproxy 处理结果时出错。比如批量、遍历、索引查询里有部分记录处理失败,这时成功的记录仍然在
MultiRecords里返回;又比如记录转 JSON 失败(-2579)。 - 响应体超过 9950000 字节:
ErrorCode = -13075,不返回记录内容。 - 索引查询(IndexQuery)没有匹配的记录:
ErrorCode = 261。 - Traverse / ListTraverse 的请求体参数错误,比如缺少
Limit、Limit小于等于 0、TraverseSession(旧版本为TraveseSession)格式错误:ErrorCode = -1811。
- 存储层返回成功,但 restproxy 处理结果时出错。比如批量、遍历、索引查询里有部分记录处理失败,这时成功的记录仍然在
400 Bad Request
- 请求阶段失败(restproxy 收到请求后、转发到存储层之前):
- HTTP 报文无法解析:
-2579,ErrorMsg为 “request format error”。 - 请求体超过 9950000 字节:
-13075。 - 缺少
x-tcaplus-target:-11539;target 不支持:-2067。 - 表不存在:
-12819。注意这里返回的是 400,不是 404。 - 其他请求头缺失或非法、请求体不是合法 JSON、字段校验失败、缺少必填字段等:一般是
-1811。 - restproxy 构造请求失败或发送请求失败:也返回 400。
ErrorCode为具体错误码,ErrorMsg一般是 “Internal Server Error” 或 “Send … Request Error”。
- HTTP 报文无法解析:
- 存储层返回下面这些错误码时:
-7949:数据版本号校验失败。Replace、List 写操作、FieldUpdate、FieldInc 会同时返回当前的RecordVersion。-1293:记录已存在。-3341:自增或自减溢出。-3853:下标越界。
- 仅 1.0 协议:批量或遍历类操作有部分记录获取失败(
-275)、字段类型不支持。同样的情况在 2.0 协议下返回 200。
401 Unauthorized
签名校验失败时返回,ErrorCode = -279,ErrorMsg = "Illegal password MD5"。1.0 和 2.0 行为一致。触发条件:
x-tcaplus-pwd-md5和业务密码的 MD5 不一致;- 没带
x-tcaplus-pwd-md5,而x-tcaplus-username和x-tcaplus-username-pwd-md5只带了其中一个,或者有一个是空值。
如果用的是用户名加密码的方式(不带 x-tcaplus-pwd-md5),校验由存储层完成。这时校验失败返回的是 500,ErrorCode 为存储层的错误码,不是 401。
404 Not Found
- 存储层返回
261:记录不存在。 - 存储层返回
-34565:索引不存在。 - 仅 1.0 协议:IndexQuery 没有匹配的记录(
ErrorCode = 261)。2.0 协议下这种情况返回 200。
408 Request Timeout
ErrorCode = -525,ErrorMsg = "request timeout"。触发场景:
- 请求发到存储层后,超过 restproxy 配置的会话超时时间(
TcapRestProxyCfg.SessionTimeout,默认 3000 ms)还没收到响应。超时是周期性扫描检查的,实际返回 408 的时间会比配置值稍晚。 - 表结构变更或表被删除时,这张表上所有还没完成的请求。
- restproxy 重新初始化存储访问时,所有还没完成的请求。
500 Internal Server Error
- 存储层返回了上面没列出的非 0 错误码。
ErrorCode为原始错误码,ErrorMsg为对应的错误描述,比如 Condition 非法、鉴权失败等。 - 存储层响应里缺少表名(
-12051),或者响应的 app、zone、table 和请求不一致(-12819,ErrorMsg为 “App Or Zone Or Table Not Match”)。 - GetRecordTotal 读取记录总数失败。
- restproxy 构造 HTTP 响应失败:
-2323,ErrorMsg为 “build response failed”。 - restproxy 的存储访问模块没有初始化成功:
-256,ErrorMsg为 “Tcaprestproxy Api Not Init”。 - 仅 1.0 协议:存储层返回成功,但 restproxy 处理结果时出错,比如取数据、反序列化、转 JSON 失败。同样的情况在 2.0 协议下返回 200。
1.0 和 2.0 的差异汇总
| 场景 | 1.0 | 2.0 |
|---|---|---|
| 存储层成功,但 restproxy 处理结果出错 | 500 | 200,ErrorCode 不为 0 |
| 批量或遍历有部分记录失败 | 400 | 200,ErrorCode 不为 0 |
| IndexQuery 没有匹配记录 | 404 | 200,ErrorCode = 261 |
| Traverse 请求体参数错误 | 400 | 200,ErrorCode = -1811 |
2. x-tcaplus-hide-default-primitive用法
作用:控制返回的 JSON 记录里是否省略“未设置”的字段。
适用协议:仅 RESTful 2.0(请求头 x-tcaplus-protocol-version: 2.0)。1.0 协议会忽略这个请求头。
取值
true(不区分大小写):开启。返回的记录里不包含“未设置”的非 repeated 字段。- 不传,或取其他值:关闭(默认)。按表结构输出全部字段,未设置的字段用默认值填充:
- 数值为
0,字符串为"",bool 为false,枚举为默认枚举值; - 子消息展开成一个由默认值组成的对象。
- 数值为
影响范围
- 只影响 restproxy 返回的记录内容,包括
Record、MultiRecords[].Record、MoreKeys。 - 不影响写入、Condition 过滤和存储的数据。
- 所有会返回记录的 2.0 接口都生效:
- GetRecord、BatchGetRecord、GetRecordByPartKey;
- FieldGet、BatchFieldGet;
- Traverse、ListTraverse;
- IndexQuery(非聚合查询)、List 系列读接口;
- 通过
x-tcaplus-result-flag返回记录的写接口。
- 不影响 GetRecordTotal 和聚合类 IndexQuery 的结果。
开启后,“未设置”的判断规则
| 字段类型 | proto2 表 | proto3 表 |
|---|---|---|
| 非 repeated 标量(数值、bool、枚举、string、bytes) | 没写入过就省略;显式写入的值即使等于默认值,也会返回 | 值等于默认值(0、""、false、编号为 0 的枚举值)就省略,不管是否显式写入过 |
| 子消息 | 没写入过就省略 | 没写入过就省略;写入过(包括写入 {})就返回 |
| repeated、map | 始终返回,空时为 [] | 同左 |
| oneof 成员 | 只返回被设置的那个成员(和开关无关) | 同左;被设置的成员即使值为 0 也会返回 |
注意事项
- 规则对嵌套子消息逐层生效。
- 和
Select一起用时,选中的字段如果属于“未设置”,同样不会出现在响应里。 - proto3 表的主键字段也适用这条规则:主键值为
0或空串时会被省略。 - 当前版本不支持 proto3 的
optional关键字。所以在 proto3 表里,标量字段“没写入”和“写入了默认值”是区分不出来的,开启后两者都会被省略。
示例(proto3)
message Inner { int32 in_v1 = 1; string in_v2 = 2; }
message Pay { int64 total_money = 1; int32 pay_times = 2; Inner msg_in = 3; repeated int32 tags = 4; }
写入 "pay": {"total_money": 1, "pay_times": 0} 后读取:
- 不带请求头(默认):
"pay": {"total_money": 1, "pay_times": 0, "msg_in": {"in_v1": 0, "in_v2": ""}, "tags": []} - 带
x-tcaplus-hide-default-primitive: true:"pay": {"total_money": 1, "tags": []}
7. 常见问题
使用RESTFul API的过程中,有疑问或者遇到报错,可参考“常见问题”和“错误码含义和处理方法”进行处理。
- restful地址建议采用北极星接入
- 北极星接入文档https://iwiki.woa.com/p/342857543 北极星接入Tcaplus常见问题排查文档
-
- 常见问题文档;
-
- 错误码含义和处理方法文档。