Files
shaguabijia-app-server/docs/API.md
T
marco c532fe966f docs: 新增 API 接口文档 + 更新后端技术方案
- 新增 docs/API.md: 全部 10 个接口的完整协议(入参/出参/错误码/鉴权)、
  复用结构(TokenPair/TokenWithUser/UserOut/CouponCard)、鉴权与刷新机制
- 更新 docs/后端技术实现.md: 目录结构同步重构后的 integrations/repositories 分层;
  补美团 CPS 模块(S-Ca 签名/feed 2外卖1到店拼接/无鉴权与sid风险);
  更新极光 RSA 密钥现状(旧密钥不配对、已重新生成);
  补已知问题与上线 checklist(JWT secret/SMS_MOCK/feed 静默吞异常)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 11:15:23 +08:00

11 KiB
Raw Blame History

傻瓜比价 App 后端 — API 接口文档

Base URL:生产 https://app-api.shaguabijia.com;本地联调 http://<开发机>:8770 协议:HTTP / JSON,请求与响应体均 application/json,字段统一 snake_case 鉴权:需鉴权的接口在请求头带 Authorization: Bearer <access_token> 最后更新:2026-05-27


通用约定

  • 时间格式:ISO 8601 UTC(如 2026-05-27T12:34:56Z
  • 错误响应:FastAPI 标准结构 {"detail": "<错误信息>"},配合语义化 HTTP 状态码:
    • 400 业务参数错(如验证码不对)
    • 401 未认证 / token 无效或过期 / 用户被禁(响应头带 WWW-Authenticate: Bearer
    • 403 账号被禁用
    • 422 请求体字段校验失败(FastAPI 自动校验,如手机号格式)
    • 429 触发限流(短信发送过频)
    • 502 上游调用失败(极光验证/解密失败、美团接口失败)
  • 接口文档(交互式):APP_ENV 非 prod 时开放 GET /docsSwagger UI)、GET /redoc;生产环境关闭。

接口总览

# 方法 + 路径 鉴权 说明
1 GET /health 健康检查
2 POST /api/v1/auth/jverify-login 极光一键登录
3 POST /api/v1/auth/sms/send 发送短信验证码(mock
4 POST /api/v1/auth/sms/login 手机号 + 验证码登录
5 POST /api/v1/auth/refresh 刷新 token
6 GET /api/v1/auth/me Bearer 获取当前登录用户
7 POST /api/v1/auth/logout Bearer 登出(服务端占位)
8 POST /api/v1/meituan/coupons 券列表 / 搜索
9 POST /api/v1/meituan/feed 首页混合推荐流
10 POST /api/v1/meituan/referral-link 换取推广链接(点"抢"时调)

⚠️ 美团三个接口当前无鉴权,且 referral-linksid 允许客户端传值覆盖默认渠道——见各接口"备注"。


复用数据结构

TokenPair

字段 类型 说明
access_token string 访问令牌,之后每个鉴权请求带 Authorization: Bearer <它>
refresh_token string 刷新令牌
token_type string 固定 "Bearer"
expires_in int access 剩余秒数(默认 7200 = 2h
refresh_expires_in int refresh 剩余秒数(默认 2592000 = 30d

TokenWithUser

继承 TokenPair 全部字段,额外多一个 userUserOut)。登录类接口成功时返回此结构。

UserOut

字段 类型 说明
id int 用户主键
phone string 手机号
nickname string | null 昵称(当前无接口可改,恒为 null
avatar_url string | null 头像(同上)
register_channel string 注册渠道:jverify / sms
status string active / disabled / deleted
created_at datetime 注册时间
last_login_at datetime 最近登录时间

CouponCard(券卡片,couponsfeeditems 元素)

字段 类型 说明
product_view_sign string 换链主键(传给 referral-link
platform int 1=外卖/到家, 2=到店
biz_line int | null 到店子类:1到餐 2到综 3酒店 4门票
name string 商品名
head_image_url string 头图
brand_name string | null 品牌名
brand_logo_url string | null 品牌 logo
sell_price string 现价
original_price string 原价
discount_amount string 优惠额 = 原价 现价
commission_rate string 佣金比例,如 "1.4%"
commission_amount string | null 预估佣金(元)
sale_volume string | null 销量
poi_name string | null 最近门店名
distance_text string | null 格式化距离,如 "600m" / "1.5km"
distance_meters float | null 原始距离(米)
available_poi_num int | null 可用门店数
coupon_num int | null 券张数
valid_days int | null 券有效天数
price_label string | null "15天低价"
rank_label string | null "2小时北京外卖销量榜第1名"
rating_label string | null "4.6分"

1. Meta

GET /health

  • 鉴权:无
  • 入参:无
  • 响应 200:{ "status": "ok" }

2. Auth 组(前缀 /api/v1/auth

2.1 POST /jverify-login — 极光一键登录

  • 鉴权:无
  • 入参:
字段 类型 必填 说明
login_token string (非空) 客户端极光 loginAuth 拿到的 loginToken
operator string (默认 "" 运营商标识 CM/CU/CT,仅用于后端日志
  • 响应 200:TokenWithUseruser.register_channel"jverify"
  • 错误:502 极光验证或 RSA 解密失败;403 账号被禁用
  • 说明:后端拿 login_token 调极光 loginTokenVerify 验真 → 取回 RSA 加密的手机号 → 用私钥解密 → 注册即登录(手机号不存在则建号)→ 签发 JWT。

2.2 POST /sms/send — 发送短信验证码

  • 鉴权:无
  • 入参:
字段 类型 必填 说明
phone string 手机号,正则 ^1\d{10}$
  • 响应 200:
字段 类型 说明
sent bool 是否已发送
mock bool 是否 mock 模式(true 时不真发,任意 6 位通过)
cooldown_sec int 多少秒后才能再次发送
  • 错误:429 发送过频(默认 60s 冷却内重复发)
  • 说明:mock 模式(SMS_MOCK=true)下不真发短信,仅记录冷却时间。

2.3 POST /sms/login — 手机号 + 验证码登录

  • 鉴权:无
  • 入参:
字段 类型 必填 说明
phone string 手机号 ^1\d{10}$
code string 验证码,长度 48
  • 响应 200:TokenWithUseruser.register_channel"sms"
  • 错误:400 验证码错误;403 账号被禁用
  • 说明:mock 模式下任意 6 位数字均通过校验。注册即登录。

2.4 POST /refresh — 刷新 token

  • 鉴权:无(凭 body 里的 refresh_token
  • 入参:
字段 类型 必填 说明
refresh_token string 有效的 refresh token
  • 响应 200:TokenPair注意:不含 user 字段
  • 错误:401 refresh token 无效/过期/类型不对,或用户不存在/被禁用
  • 说明:服务端校验 refresh token(验签 + 验过期 + 验类型为 refresh)并查库确认用户仍 active,然后签发全新的 access+refresh 对。客户端在请求收到 401 时由 OkHttp Authenticator 自动调用。

2.5 GET /me — 获取当前登录用户

  • 鉴权: Bearer access_token
  • 入参:无(身份取自 Header token
  • 响应 200:UserOut
  • 错误:401 未带 token / token 无效或过期 / 用户被禁用

2.6 POST /logout — 登出

  • 鉴权: Bearer access_token
  • 入参:无
  • 响应 200:{ "ok": true }
  • 说明:服务端无状态、不吊销 token(占位实现),真正失效靠客户端删除本地 token。后续若加 jti 黑名单可在此写入。

3. 美团 CPS 组(前缀 /api/v1/meituan,全部无鉴权

3.1 POST /coupons — 券列表 / 搜索

  • 鉴权:无
  • 入参:
字段 类型 必填 默认 说明
longitude float 经度
latitude float 纬度
platform int 1 1=外卖/到家, 2=到店
biz_line int null 到店子类:1到餐 2到综 3酒店 4门票
list_topic_id int 3 榜单:1精选 2今日必推 3爆款筛选 5限时筛选
keyword string null 搜索词(填了则忽略 list_topic_id,走搜索
sort_field int null 1价格 2销量 6离我最近(搜索时默认 6)
search_id string null 翻页 token,首页不填
page int 1 ≥1
page_size int 20 120
  • 响应 200:{ items: CouponCard[], has_next: bool, search_id: string|null }
  • 错误:502 美团接口失败
  • 备注:当前 Android 客户端未调用此接口(搜索功能尚未实现),仅后端实现完整。

3.2 POST /feed — 首页混合推荐流

  • 鉴权:无
  • 入参:
字段 类型 必填 默认 说明
longitude float 经度
latitude float 纬度
page int 1 ≥1
page_size int 20 120
  • 响应 200:{ items: CouponCard[], has_next: bool, page: int }
  • 备注:后端在 coupons 之上封装的"伪推荐"——每页并发拉一次外卖、一次到店(到餐)榜单,按 2 外卖 + 1 到店 交叉去重。榜单组合写死 3 页(第1页爆款、第2页今日必推、第3页外卖精选+到店限时),第 3 页起 has_next=false、第 4 页返空⚠️ 可观测性盲区:feed 内部对美团调用异常是静默吞掉返回空列表(不报 502、不打日志)。若 items 为空但无错误,优先用 coupons 接口逼出真实错误(它会以 502 暴露,如"MT_CPS_APP_KEY not configured")。

3.3 POST /referral-link — 换取推广链接

  • 鉴权:无
  • 入参:
字段 类型 必填 默认 说明
product_view_sign string 券的换链主键(来自 CouponCard
platform int 1 1=外卖/到家, 2=到店
biz_line int null 到店子类
sid string 服务端默认 sgbjia 渠道追踪标识
link_type_list int[] [1, 3] 1=H5长链 2=H5短链 3=deeplink
  • 响应 200:
字段 类型 说明
link string 默认推广链接(按 data > H5(1) > deeplink(3) > 任意 兜底)
link_map object 各类型链接 { "linkType": "url" },如 {"1": "<H5>", "3": "<deeplink>"}
  • 错误:502 美团接口失败
  • 备注:客户端实际优先用 link_map["3"]deeplink)拉起美团 App,失败降级 link_map["1"]H5)。 ⚠️ 安全:sid 允许客户端传值覆盖服务端默认渠道,理论上他人可借本接口刷自己渠道的分佣;建议服务端锁定 sid、忽略客户端传值。

附:鉴权与刷新机制

  • 签发:登录成功后签发 access(HS256,2h) + refresh(30d),payload 含 sub(user_id)、typ(access/refresh)、iatexp
  • 携带:客户端对需鉴权接口自动加 Authorization: Bearer <access>(登录类接口跳过)。
  • 校验/me/logout:验签 → 验过期 → 验 typ=access → 查库确认用户存在且 status=active,任一不过 → 401。
  • 续期:access 过期触发 401 → 客户端用 refresh 调 /refresh 换新 token 对并重放原请求;refresh 也失效 → 清本地、跳登录。
  • 无状态:token 不落库,服务端无法主动吊销(logout 为占位),靠短 access 有效期限制泄露风险。JWT 密钥 JWT_SECRET_KEY 必须为高熵随机串(生产严禁用默认值)。