export type CookieOptions = { path?: string domain?: string expires?: Date | string | number maxAge?: number secure?: boolean httpOnly?: boolean sameSite?: 'lax' | 'strict' | 'none' } export function serializeCookie(name: string, value: string, options: CookieOptions = {}): string { const enc = encodeURIComponent let cookie = `${name}=${enc(value)}` if (options.maxAge != null) cookie += `; Max-Age=${Math.floor(options.maxAge)}` if (options.expires != null) { const date = typeof options.expires === 'number' ? new Date(options.expires) : new Date(options.expires) cookie += `; Expires=${date.toUTCString()}` } if (options.domain) cookie += `; Domain=${options.domain}` if (options.path) cookie += `; Path=${options.path}` if (options.secure) cookie += `; Secure` if (options.httpOnly) cookie += `; HttpOnly` if (options.sameSite) cookie += `; SameSite=${options.sameSite === 'none' ? 'None' : options.sameSite === 'lax' ? 'Lax' : 'Strict'}` return cookie } export function parseCookieHeader(header: string | undefined): Record { const raw = header || '' const out: Record = {} raw.split(';').map(s => s.trim()).filter(Boolean).forEach(kv => { const idx = kv.indexOf('=') const k = idx >= 0 ? kv.slice(0, idx) : kv const v = idx >= 0 ? decodeURIComponent(kv.slice(idx + 1)) : '' out[k] = v }) return out } export function parseDocumentCookies(): Record { if (typeof document === 'undefined') return {} return parseCookieHeader(document.cookie) } /** // server 侧中间件 import { parseCookieHeader, serializeCookie } from './src/compose/cookieUtils' app.use(async (ctx, next) => { const cookies = parseCookieHeader(ctx.request.headers.cookie as string) // 读取 const token = cookies['demo_token'] // 写入(HttpOnly 更安全) if (!token) { const setItem = serializeCookie('demo_token', 'from-mw', { httpOnly: true, path: '/', sameSite: 'lax' }) ctx.set('Set-Cookie', [setItem]) } await next() }) */