避坑:三大接入点返回字段大小写不一致,解析代码怎么写才稳
# 避坑:三大接入点返回字段大小写不一致,解析代码怎么写才稳
> 接口/接入点:猜一猜谜语 API(151-2 / 151-3 / 151-4) · 免费 · 适用人群:所有需写解析代码的开发者 · 阅读时间:约 5 分钟
## 核心要点
- 同一接口三个接入点返回字段命名不统一:151-2 用 `Title`/`Answer`(大写),151-4 用 `title`/`answer`(小写),151-3 是 `typeList[id/name]`。
- 根对象命名也不同:151-2 是 `pagebean`,151-4 是 `pb`,151-3 无分页对象。
- 稳的写法:**先判字段存在性再取值**,用一个统一适配器屏蔽差异,别硬编码某个接入点的键名。
## Why:为什么这篇是避坑必读
照抄 151-2 的 `item.Title` 去解析 151-4,会得到 `undefined`;把 151-3 当谜面列表解析会崩溃。一次写对适配器,后面三个接入点都能复用。
## What:差异总览
| 接入点 | 谜面键 | 谜底键 | 列表根 | 分页对象 |
|--------|--------|--------|--------|---------|
| 151-2 | `Title` | `Answer` | `pagebean.contentlist` | `pagebean` |
| 151-4 | `title` | `answer` | `pb.contentlist` | `pb` |
| 151-3 | (无,仅类型) | (无) | `typeList` | 无 |
## How:统一适配器
### Python 适配器(兼容三套)
```python
def parse_riddle(rb):
"""返回 list[dict],每项含 title/answer/typeId/typeName(类型查询仅有 id/name)。"""
# 151-2:pagebean.contentlist(大写 Title/Answer)
if "pagebean" in rb:
return [{
"title": i.get("Title"), "answer": i.get("Answer"),
"typeId": i.get("typeId"), "typeName": i.get("typeName"),
} for i in rb["pagebean"].get("contentlist", [])]
# 151-4:pb.contentlist(小写 title/answer)
if "pb" in rb:
return [{
"title": i.get("title"), "answer": i.get("answer"),
"typeId": i.get("typeId"), "typeName": i.get("typeName"),
} for i in rb["pb"].get("contentlist", [])]
# 151-3:typeList(id/name)
if "typeList" in rb:
return [{"typeId": t.get("id"), "typeName": t.get("name")}
for t in rb["typeList"]]
# 兼容 151-2 扁平单条形态(OpenAPI schema 描述)
if "Title" in rb or "title" in rb:
return [{
"title": rb.get("Title") or rb.get("title"),
"answer": rb.get("Answer") or rb.get("answer"),
"typeId": rb.get("typeId"), "typeName": rb.get("typeName"),
}]
return []
```
### JavaScript 适配器
```javascript
function parseRiddle(rb) {
if (rb.pagebean) return rb.pagebean.contentlist.map(i => ({
title: i.Title, answer: i.Answer, typeId: i.typeId, typeName: i.typeName }));
if (rb.pb) return rb.pb.contentlist.map(i => ({
title: i.title, answer: i.answer, typeId: i.typeId, typeName: i.typeName }));
if (rb.typeList) return rb.typeList.map(t => ({ typeId: t.id, typeName: t.name }));
if (rb.Title || rb.title) return [{
title: rb.Title || rb.title, answer: rb.Answer || rb.answer,
typeId: rb.typeId, typeName: rb.typeName }];
return [];
}
```
## 返回示例与解析
调用任一接入点后,先取 `showapi_res_body`,再交给上面的 `parse_riddle`,不要直接 `rb.contentlist`。完整字段见 [返回字段全解](https://www.showapi.com/guides/riddle-response-fields-151)。
## 进阶/边界
- **别假设键名**:151-2 大写、151-4 小写,统一用 `.get()` / 可选链,避免 `undefined` 抛错。
- **分页字段为字符串**:151-4 的 `allNum`/`allPage` 是字符串,比较前 `int()`。
- **151-2 结构文档矛盾**:返回示例是 `pagebean.contentlist` 数组,字段表/OpenAPI 是扁平单条;适配器已兼容两种形态。
- **151-3 无谜面谜底**:它是类型列表,适配后只有 `typeId`/`typeName`,别当题目用。
## FAQ
**Q1:适配器会不会漏掉扁平形态?**
不会,已包含 151-2 扁平单条(OpenAPI schema 描述)的兼容分支。
**Q2:为什么 151-2 和 151-4 大小写不一样?**
官方各接入点返回定义如此,文档未统一,我们只能在代码层兼容。
**Q3:151-3 解析出来没有 title 正常吗?**
正常,151-3 是类型查询,只返回 `id`/`name`,没有谜面谜底。
**Q4:分页 total 怎么拿?**
151-2 用 `rb.pagebean.allNum`,151-4 用 `rb.pb.allNum`;151-4 是字符串,先转 int。
**Q5:ret_code 在哪?**
在 `showapi_res_body` 内;系统级 `showapi_res_code` 在外层,两者别混。
## 相关能力 / 下一步阅读
- [猜一猜谜语 API 返回字段全解:三大接入点的 Title/Answer 与分页差异](https://www.showapi.com/guides/riddle-response-fields-151)
- [按类型与分页查询谜语:151-4 接入点实战("关键词"真相)](https://www.showapi.com/guides/riddle-search-by-type-151)
- [猜一猜谜语 API 类型清单:26 类谜语 typeId 完整对照表](https://www.showapi.com/guides/riddle-typelist-151)
- **本系列共 13 篇**:查看[猜一猜谜语 API 指南总目录](https://www.showapi.com/guides/riddle-guides-151)