一、幂等键与约束function validKey(k: string): boolean { return /^[A-Za-z0-9_\-\.]{8,128}$/.test(k) }

二、请求哈希与存储import crypto from 'crypto'

function requestHash(path: string, body: any): string {

const s = path + ':' + JSON.stringify(body)

return crypto.createHash('sha256').update(s).digest('hex')

}

type Entry = { key: string; hash: string; status: number; body: string; expireAt: number }

class Store {

map = new Map<string, Entry>()

ttlSec: number

constructor(ttlSec: number) { this.ttlSec = ttlSec }

get(k: string): Entry | undefined {

const e = this.map.get(k)

if (!e) return undefined

if (Date.now() > e.expireAt) { this.map.delete(k); return undefined }

return e

}

set(k: string, e: Entry) { this.map.set(k, e) }

}

三、并发锁与防重放class Lock {

locks = new Set<string>()

acquire(k: string): boolean { if (this.locks.has(k)) return false; this.locks.add(k); return true }

release(k: string) { this.locks.delete(k) }

}

四、路由中间件type Req = { headers: Record<string, string | undefined>; path: string; body: any }

type Res = { status: (n: number) => Res; end: (b?: string) => void; setHeader: (k: string, v: string) => void }

function idempotencyGuard(store: Store, lock: Lock) {

return async function handler(req: Req, res: Res, next: Function) {

const key = req.headers['idempotency-key'] || ''

if (!validKey(key)) return res.status(400).end('invalid_idempotency_key')

const h = requestHash(req.path, req.body)

const cached = store.get(key)

if (cached) {

if (cached.hash !== h) return res.status(409).end('key_conflict')

res.setHeader('Idempotency-Replayed', 'true')

return res.status(cached.status).end(cached.body)

}

if (!lock.acquire(key)) return res.status(409).end('in_progress')

try {

;(req as any).idemKey = key

;(req as any).idemHash = h

next()

} finally {

lock.release(key)

}

}

}

function recordResponse(store: Store, req: Req, status: number, body: string) {

const key = (req as any).idemKey as string

const hash = (req as any).idemHash as string

const ttlSec = 900

const expireAt = Date.now() + ttlSec * 1000

store.set(key, { key, hash, status, body, expireAt })

}

五、示例与验收键格式长度与字符约束通过;TTL≤900秒;冲突返回`409`。重复请求响应复用并带`Idempotency-Replayed`;并发锁避免重复执行。存储包含状态与响应体,过期后自动清理并拒绝旧键复用。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部