快速开始
按道具 ID 或名称查询道具信息与展示图片。只读、免鉴权、支持跨域,直接 GET 就能用。
1. 搜一个道具,拿到它的 itemid:
curl '/search?q=星梦茶会&limit=3'
2. 响应里每条都带图片地址,image 可以直接放进 <img src>:
{
"query": "星梦茶会",
"total": 6,
"count": 3,
"items": [
{
"itemid": 158961,
"name": "星梦茶会套装",
"category": "avatar", "category_name": "装扮",
"subcategory": "asm_base", "subcategory_name": "套装",
"image": "/img/158961.png",
"images": ["/img/158961.png"]
}
]
}
3. 已知 ID 就直接取:
curl '/items/158961'
三步就够了。剩下的接口都是围绕这两件事展开的:怎么找到道具、怎么按分类浏览。
中文关键词少于 3 个字会慢一些。全文索引按 3 字符切分,「天使」「幻影」这类 两字词走不了索引,响应约 40 ms(三字以上约 1 ms)。功能完全正常,只是别用它做 输入即搜的联想。
几个概念
道具分两层分类
粗分类 category 只有 6 个,对应游戏商城的 Tab;细分类 subcategory
有 200 多个,来自客户端自己的分类表,不是自己编的。
| code | 名称 | 典型细分类 |
|---|---|---|
kart | 赛车 | car_new_a A级赛车、cr_tail 尾挂 |
avatar | 装扮 | asm_base 套装、rr_hair 发饰 |
function | 功能 | 各类卡片、道具 |
pet | 宠物 | 宠物、宠物装扮 |
gem | 宝石 | dmd_speedskill 圆形竞速宝珠 |
other | 其他 | 角色、系统保留 |
完整的两层对照表随时可查:GET /categories。
车系是另一条线
series 和 subcategory 正交 —— 一个车头既属于「车头」也属于
「雷诺配件」。两个一起传是 AND。
图片
image 是首选的一张,images 是全部(主图、_b/_c
变体、动画帧)。约一半道具有图,没有的 image 是 null,
images 是 []。图片由 Nginx 直出,可放心并发拉。
万能查询
/lookup?q=一个入口吃三种输入:道具 ID、图片名、道具名。 不用先判断手上这串东西是什么,直接丢进来。
curl '/lookup?q=171055' # 道具 ID curl '/lookup?q=171055.png' # 图片名 curl '/lookup?q=20133_b.png' # 图片变体,会还原到道具 20133 curl '/lookup?q=甜酷CP-麒麟' # 道具名
返回体固定这个形状,items 里每条的结构和其他接口完全一样:
{
"query": "20133_b.png",
"matched_by": "image",
"total": 1,
"items": [ { "itemid": 20133, "name": "双髻鲨", "image": "…/20133.png", … } ]
}
| 参数 | 默认 | 说明 |
|---|---|---|
q | 必填 | 道具 ID、图片名(带不带 .png 都行)或道具名 |
limit | 20 | 最多返回几条,1–200。total 是命中总数,不受它影响 |
matched_by 告诉你它是按什么命中的,便于判断结果可不可信:
| 值 | 含义 |
|---|---|
itemid | 按道具 ID 命中 |
image | 按图片名命中(输入带 .png 或带 _b 这类变体后缀) |
name_exact | 名字完全相同 |
name_fuzzy | 名字包含关键词,按相关度排序 |
none | 没查到。仍然是 200,total 为 0、items 为 [] |
为什么图片名能当 ID 用:全库 68,358 张图的文件名前导数字恒等于它所属的
itemid(实测 0 例外)。所以 171055、171055.png、
20133_b 走的是同一条路径。
这个接口的覆盖范围比其他接口大。/items/{id} 只有有图的
67,374 条,而这里覆盖全部 135,689 条,外加 154 张没有道具记录的图片。
查不到图或查不到道具时,对应字段是 null / [],结构不变:
- 有道具无图 →
image为null、images为[]、分类等字段为null - 有图无道具(孤儿图)→
name是空字符串,图片字段正常
名字有一半不唯一。73,231 个不重复名字里有 33,661 个对应多条道具
(子件 1,737 条、赛车卡 529 条、作废id 344 条…)。
所以 别默认取 items[0] 就完事 —— 先看 total。
搜索道具
/search只按名称搜索,中文子串匹配,按相关度排序。
| 参数 | 默认 | 说明 |
|---|---|---|
q | 必填 | 关键词。空格分隔多个词表示都要出现(q=天使 套装) |
limit | 20 | 每页条数,最大 100 |
offset | 0 | 跳过多少条,用于翻页 |
category | 不限 | 粗分类,逗号分隔可多传 |
subcategory | 不限 | 细分类,逗号分隔可多传 |
sort | relevance | 还可以是 id(ID 升序)、newest(ID 倒序) |
facets | true | 返回各分类命中数,前端拿去做 Tab。不需要就传 false,响应小很多也更快 |
field | name | 传 all 连描述一起搜 —— 会捞进一堆名字不相关的,慎用 |
/search?q=雷诺&category=kart 雷诺相关的赛车 /search?q=天使&subcategory=car_new_a 只要 A级赛车 /search?q=天使&limit=5&facets=false 只要结果,不要分类统计
响应在 items 之外还有 total(总命中)、
categories / subcategories(各分类命中数,facets=true 时)。
查单个
/items/{itemid}查不到返回 404。加 ?full=true 额外返回 restype、
itemselltype、modify_time 和 raw(客户端原始记录,
字段很多,一般用不上)。
curl '/items/158961' curl '/items/158961?full=true'
批量查
/batch?ids=逗号分隔,一次最多 200 个。返回顺序与传入顺序一致,查不到的不占位、
单独列在 missing 里。
curl '/batch?ids=158961,10008,12720'
{"requested":3, "found":2, "missing":[12720], "items":[…]}
展示一批道具时用这个,别循环调单个接口。
分页列表
/items不带关键词地按条件翻页。
| 参数 | 默认 | 说明 |
|---|---|---|
page | 1 | 页码,从 1 开始 |
size | 50 | 每页条数,最大 100 |
category subcategory series | 不限 | 逗号分隔可多传 |
itemtype garagetype sextype | 不限 | 客户端原始枚举值,见 /enums |
has_image | 不限 | 只要有图 / 无图的 |
/items?subcategory=car_new_s&size=50 所有 S级赛车 /items?subcategory=car_new_a,car_new_b A车 + B车 /items?series=other_refititem_renault 雷诺车系全部配件 /items?category=avatar&page=2&size=100 装扮第 2 页
响应带 total 和 pages,直接拿去渲染分页器。
分类表
/categories两层分类树,每层带道具数量。做分类导航就靠它,别把 code 写死在前端。
{"categories":[
{"code":"kart","name":"赛车","count":3493,
"subcategories":[
{"code":"car_new_a","name":"A级赛车","itemtype":1539,"count":729},
{"code":"car_new_s","name":"S级赛车","itemtype":1543,"count":177}
]}
]}
加 ?empty=true 连一条道具都没有的分类也列出来;
加 ?has_image=true 只统计有图的。
车系表
/series车系配件对照表,配合 /items?series= 用。
枚举表
/enums客户端原始常量的数值 → 名称映射(itemtype、garagetype、
sextype 等)。一般用不上 —— 响应里已经带了 *_name 字段。
数据统计
/stats道具/图片总数、各分类数量、最常见的 itemtype。另有
GET /healthz 供监控探活,返回 {"ok":true,"items":67369}。
ID 名称对照表
全部 135,689 个道具的 itemid + 名字,静态文件直接下载,
不用调接口。适合在本地做 ID 反查、批量校对、离线搜名字。
| 文件 | 大小 | 格式 |
|---|---|---|
/download/qqspeed-items-idname.csv | 5.8 MB | UTF-8 带 BOM,Excel 直接打开不乱码 |
/download/qqspeed-items-idname.jsonl | 11 MB | 每行一个 JSON 对象 |
curl -O '/download/qqspeed-items-idname.csv'
CSV 三列,JSONL 三个字段:
itemid,name,sources
10008,"腾彩气球",ItemList|Client1
{"itemid":10008,"name":"腾彩气球","sources":["ItemList","Client1"]}
| 字段 | 说明 |
|---|---|
itemid | 道具 ID,唯一,可直接用于 /items/{itemid} |
name | 道具名。有 401 条是空字符串 —— 客户端里本来就没给名字 |
sources | 该 ID 出现在哪几个客户端道具表文件里,排查用,一般可忽略 |
这份表是全量 135,689 条,比接口的默认数据集大一倍 ——
接口只收录有展示图的 67,374 条,其余 68,315 条多为无展示图的功能性道具,
用 /items/{itemid} 查会返回 404。表里有的 ID 不等于接口查得到。
只要有图的那部分,筛 sources 没用,得改用 /items?has_image=true 翻页。
游戏更新后这份文件才会变,不是实时的。缓存 1 小时。
响应字段
所有返回道具的接口,单条道具的结构都一样:
| 字段 | 类型 | 说明 |
|---|---|---|
itemid | int | 道具 ID,唯一 |
name | string | 道具名 |
description | string|null | 描述 |
usagedesc | string|null | 用途说明 |
category / category_name | string|null | 粗分类 code 与中文名 |
subcategory / subcategory_name | string|null | 细分类 code 与中文名 |
series / series_name | string|null | 车系 code 与中文名 |
itemtype / itemtype_name | int|null | 客户端原始类型 |
garagetype / sextype | int|null | 商城分栏 / 性别限制(0 通用 1 男 2 女) |
create_time | string|null | 客户端记录的创建时间 |
has_image | bool | 有没有展示图 |
image_count | int | 图片张数 |
image | string|null | 首选图片完整地址 |
images | string[] | 全部图片地址,无图时是 [] |
可能为 null 的字段一定存在,不会整个消失。解析时按「值可能是 null」
处理即可,不用判断字段存不存在。
错误码
| 状态码 | 什么时候 | 响应体 |
|---|---|---|
400 | 分类 code 不认识、ids 为空或超过 200 个 | {"detail":"未知分类 nope,可选值见 /categories"} |
404 | 道具不存在 | {"detail":"道具不存在: 999999999"} |
422 | 参数类型/范围不对,如 limit=500 | {"detail":[{"loc":["query","limit"],"msg":"…"}]} |
429 | 超过限流(单 IP 20 次/秒,突发 40) | Nginx 默认页 |
400 / 404 的 detail 是字符串,422 的是数组。两种都要能处理 ——
最省事的写法是只看状态码,需要展示原因时再判断 detail 的类型。
标识你的应用
可选。带上它,你的调用就能被单独统计出来,而不是跟别人混在一起按 IP 猜。
每次请求加一个请求头,值自己起,8~64 个字符,只能用字母、数字和 - _ . ::
curl -H 'X-Client-Id: myapp-prod-01' '/search?q=天使'
不方便加请求头(比如直接在浏览器地址栏、或者小程序里拼 URL)就用查询参数,效果一样:
/search?q=天使&client_id=myapp-prod-01
不带也能正常用,接口行为、返回内容、限流都完全不受影响 —— 这个值只进统计, 不参与鉴权,也不做配额。
为什么建议带上
不带的话只能靠 IP + User-Agent 认人:你的服务换台机器、或者用户从 WiFi 切到 4G, 就会被当成新的调用方;反过来,同一个出口 IP 后面的一堆人会被算成一个。 带上之后这些都不会错。
值要固定,别每次启动随机生成 —— 那跟不带没区别。多环境建议区分开,
例如 myapp-prod / myapp-test,出问题时好定位是哪一边打的。
里面别放用户 ID、手机号之类的个人信息,一个应用一个值就够了。