44 lines
1.3 KiB
TypeScript
44 lines
1.3 KiB
TypeScript
import { Router } from 'express'
|
||
|
||
import { createRateLimitMiddleware, getBodyFieldRateLimitKey } from '../middleware/rate-limit.js'
|
||
import { confirmRedeemOrder, lookupRedeemOrder } from '../services/redeem/redeem-service.js'
|
||
import { createRouteHandler } from '../utils/http.js'
|
||
|
||
/**
|
||
* 固定兑换链接的后端接口(前端页面在 `https://<域名>/redeem`)。
|
||
*
|
||
* 公开接口(无需登录),但按「订单号 + IP」限流:这是无 token 方案的第一道防线
|
||
* (见 docs/抖音-码速达/05-最小接入方案分析.md §3.2)。
|
||
* 订单资料与进度查询已统一到 `/api/v1/o`(routes/order-service.ts)。
|
||
*/
|
||
const router = Router()
|
||
|
||
const redeemRateLimit = createRateLimitMiddleware({
|
||
scope: 'redeem',
|
||
windowMs: 60_000,
|
||
max: 60,
|
||
key: getBodyFieldRateLimitKey('orderNo'),
|
||
})
|
||
|
||
router.post(
|
||
'/lookup',
|
||
redeemRateLimit,
|
||
createRouteHandler((req) => lookupRedeemOrder({ orderNo: req.body?.orderNo }), {
|
||
successMessage: 'ok',
|
||
errorMessage: '查询订单失败',
|
||
scope: '[redeem/lookup]',
|
||
}),
|
||
)
|
||
|
||
router.post(
|
||
'/confirm',
|
||
redeemRateLimit,
|
||
createRouteHandler((req) => confirmRedeemOrder({ orderNo: req.body?.orderNo }), {
|
||
successMessage: '兑换完成',
|
||
errorMessage: '兑换失败',
|
||
scope: '[redeem/confirm]',
|
||
}),
|
||
)
|
||
|
||
export default router
|