# 美团联盟 CPS 开放接口（meituan）

> 文件:`app/integrations/meituan.py` | 关联接口:[meituan-coupons](../api/meituan-coupons.md) · [meituan-feed](../api/meituan-feed.md) · [meituan-referral-link](../api/meituan-referral-link.md) | [← 集成索引](./README.md)

## 作用
调美团联盟 CPS 开放接口：查券（列表/搜索）+ 换推广链。

## 函数 / 异常
| 函数 | 说明 |
|---|---|
| `query_coupon(...)` | 券查询/搜索 → `/cps_open/common/api/v1/query_coupon` |
| `get_referral_link(...)` | 换推广链 → `/cps_open/common/api/v1/get_referral_link` |
| 异常 `MeituanCpsError` | HTTP 错误 / 业务 `code != 0`，api 层翻成 `502` |

## 签名机制（关键）
类阿里云网关 **S-Ca** 头，但 `stringToSign` **只有 4 段**：
```
METHOD\n + Content-MD5\n + Headers(按 key 升序 "k:v\n") + Url
```
**没有 Accept / Content-Type / Date 行**（加了就签名失败）。签名 = HMAC-SHA256(stringToSign, AppSecret) 的 base64。参与签名的头:`S-Ca-Timestamp,S-Ca-App`（在 `S-Ca-Signature-Headers` 里声明）。

## 入参换算 / 坑
- 经纬度 **× 1_000_000 取整**传给美团。
- 榜单字段是 **`listTopiId`**（美团接口的拼写，少个 `c`，别"纠正"成 `listTopicId`）。
- 有 `searchText` 时走搜索、`sort_field` 默认 6（离我最近）；否则按 `listTopiId` 出榜单。
- 换链 `sid` 不传则用 `MT_CPS_DEFAULT_SID`；`linkTypeList` 默认 `[1,3]`。

## 配置
| 配置项 | 说明 |
|---|---|
| `MT_CPS_APP_KEY` / `MT_CPS_APP_SECRET` | CPS 网关 AppKey / AppSecret |
| `MT_CPS_HOST` | 网关 host |
| `MT_CPS_DEFAULT_SID` | 默认推广位 sid（渠道） |
| `MT_CPS_TIMEOUT_SEC` | 请求超时 |

## 未配凭证时降级(2026-05-28 引入)
api 层 3 个端点都在入口处 `if not settings.mt_cps_configured:` 早返空(`coupons` 返空数组、`feed` 返空 items、`referral-link` 返 `link=""` + `link_map={}`),**不报 502**。

**为什么这么设计**:新开发机没填 `MT_CPS_APP_KEY` 时,首页一进就拉 `/feed` → 502 → 整屏错误,首屏体验差。降级后端业务可以先跑起来,等真要测美团 CPS 再补 key。

**坏副作用**:`feed` 本来就有"已配凭证但美团调用失败时 `_fetch_topic` 静默吞错"的可观测性盲区,加上"未配凭证时也返空",**两种空结果路径在响应上无法区分**。排障路径:
- `/health` 接口暴露 `mt_cps_configured: bool`——先看配置
- 改调 `/coupons` 让"已配凭证但调用失败"以 502 + 错误文案暴露细节

## feed 调用静默吞错
`api/v1/meituan.py` 的 `_fetch_topic` 对 `MeituanCpsError` `except 返回 []` 且**不打日志**。导致美团接口失败时 `feed` 返 200 + 空 items 无声失败。建议补一条 `logger.error` 至少留痕,真实排障还得改调 `coupons`(它在配置就绪时以 502 暴露)。

## 备注
- 美团接口当前**无鉴权**,且换链的 `sid` 允许客户端传值覆盖默认渠道——见对应 api 文档「备注」
- 未配凭证降级、feed 静默吞错都在 [待办与技术债.md](../guides/待办与技术债.md) 已记账
