一、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-*`头;发布与回滚路径可审计与复盘。

发表评论 取消回复