一、目标与约束精确来源白名单;凭证模式下禁止`*`;按路由/方法/头维度控制。预检响应必须设置`Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers`与合理`Max-Age≤600`。二、策略定义type CorsRule = { origin: string; routes: Record<string, { methods: string[]; headers: string[]; credentials: boolean }> } const rules: CorsRule[] = [ { origin: 'https://example.com', routes: { '/api/user': { methods: ['GET','POST'], headers: ['Content-Type','Authorization'], credentials: true } } } ] 三、匹配与响应type Req = { method: string; path: string; headers: Record<string, string | undefined> } type Res = { setHeader: (k: string, v: string) => void; status: (n: number) => Res; end: (b?: string) => void } function matchRule(origin: string, path: string): { methods: string[]; headers: string[]; credentials: boolean } | null { const r = rules.find(x => x.origin === origin) if (!r) return null const conf = r.routes[path] return conf || null } function applySimple(req: Req, res: Res) { const origin = req.headers['origin'] || '' const conf = matchRule(origin, req.path) if (!conf) return res.setHeader('Access-Control-Allow-Origin', origin) res.setHeader('Vary', 'Origin') if (conf.credentials) res.setHeader('Access-Control-Allow-Credentials', 'true') } 四、预检处理function preflight(req: Req, res: Res) { const origin = req.headers['origin'] || '' const method = req.headers['access-control-request-method'] || '' const hdrs = (req.headers['access-control-request-headers'] || '').split(',').map(s => s.trim()).filter(Boolean) const conf = matchRule(origin, req.path) if (!conf) return res.status(403).end('cors_forbidden') if (!conf.methods.includes(method)) return res.status(405).end('method_not_allowed') for (const h of hdrs) if (!conf.headers.map(x => x.toLowerCase()).includes(h.toLowerCase())) return res.status(400).end('header_not_allowed') res.setHeader('Access-Control-Allow-Origin', origin) res.setHeader('Access-Control-Allow-Methods', conf.methods.join(',')) res.setHeader('Access-Control-Allow-Headers', conf.headers.join(',')) res.setHeader('Access-Control-Max-Age', '600') if (conf.credentials) res.setHeader('Access-Control-Allow-Credentials', 'true') res.setHeader('Vary', 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers') return res.status(204).end() } 五、整合与验收function corsMiddleware(req: Req, res: Res, next: Function) { const origin = req.headers['origin'] || '' const conf = matchRule(origin, req.path) if (!conf) return next() if (req.method === 'OPTIONS') return preflight(req, res) applySimple(req, res) next() } 白名单来源精确匹配;凭证模式不使用`*`;路由/方法/头严格控制。预检缓存`Max-Age≤600`且`Vary`包含请求方法与头;简单请求返回允许来源与可选凭证。审计包含来源、路由与方法;拒绝时返回明确错误码与原因。

发表评论 取消回复