一、Flag定义与上下文type FlagRule = { name: string; percent: number; allowUsers?: string[]; denyUsers?: string[]; allowTenants?: string[]; deviceRegex?: RegExp }
type Context = { userId: string; tenantId: string; device: string }
二、参数校验function validPercent(p: number): boolean { return Number.isFinite(p) && p >= 0 && p <= 100 }
function inList(id: string, list?: string[]): boolean { return !!list && list.includes(id) }
三、决策与审计function hashId(id: string): number { let h = 0; for (const c of id) h = (h * 31 + c.charCodeAt(0)) >>> 0; return h % 100 }
type Decision = { enabled: boolean; reason: string }
function decide(rule: FlagRule, ctx: Context): Decision {
if (!validPercent(rule.percent)) return { enabled: false, reason: 'invalid_percent' }
if (inList(ctx.userId, rule.denyUsers)) return { enabled: false, reason: 'deny_user' }
if (inList(ctx.tenantId, rule.allowTenants)) return { enabled: true, reason: 'allow_tenant' }
if (inList(ctx.userId, rule.allowUsers)) return { enabled: true, reason: 'allow_user' }
if (rule.deviceRegex && !rule.deviceRegex.test(ctx.device)) return { enabled: false, reason: 'device_not_match' }
const bucket = hashId(ctx.userId + ':' + ctx.tenantId)
return bucket < rule.percent ? { enabled: true, reason: 'by_percent' } : { enabled: false, reason: 'by_percent' }
}
四、风控与回滚type RiskEvent = { userId: string; tenantId: string; flag: string; score: number; timestamp: string }
function risky(evt: RiskEvent, threshold: number): boolean { return evt.score >= threshold }
function rollback(rule: FlagRule): FlagRule { return { ...rule, percent: 0 } }
五、整合中间件type Req = { headers: Record<string, string | undefined> }
type Res = { setHeader: (k: string, v: string) => void }
function getCtx(req: Req): Context {
return { userId: req.headers['x-user-id'] || 'anon', tenantId: req.headers['x-tenant-id'] || 'anon', device: req.headers['user-agent'] || '' }
}
function flagMiddleware(req: Req, res: Res, rule: FlagRule, emit: (d: Decision) => void) {
const ctx = getCtx(req)
const d = decide(rule, ctx)
res.setHeader('X-Flag-' + rule.name, d.enabled ? 'on' : 'off')
emit(d)
}
六、验收清单`percent`在0-100范围并生效;白/黑名单优先于百分比;设备正则按需匹配。风控事件触发阈值后自动回滚到`percent=0`;审计包含启用原因与用户/租户。中间件响应带`X-Flag-*`头;发布与回滚路径可审计与复盘。

发表评论 取消回复