'use strict'; const { API_CODES, ApiError } = require('./api-codes'); /** * JSON 安全化:BigInt 无法被 JSON.stringify 序列化(直接抛 TypeError); * Date 统一转 ISO 字符串。 * @param {any} value * @returns {any} */ function sanitize(value) { if (value === null || value === undefined) return value; if (typeof value === 'bigint') { return value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : value.toString(); } if (value instanceof Date) return value.toISOString(); if (Array.isArray(value)) return value.map(sanitize); if (typeof value === 'object') { const out = {}; for (const [k, v] of Object.entries(value)) out[k] = sanitize(v); return out; } return value; } /** 统一成功响应:{ code:0, message:'ok', data }(migration-plan §6.1) */ function ok(res, data) { res.json({ code: API_CODES.OK, message: 'ok', data: sanitize(data) }); } /** * 包装异步路由 handler,自动 catch 转交 error 中间件。 * 用法:router.get('/x', asyncHandler(async (req,res) => {...})) * @param {(req: any, res: any, next: any) => Promise} fn */ function asyncHandler(fn) { return (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next); } /** Express 全局错误中间件(4 参数) */ // eslint-disable-next-line no-unused-vars function errorMiddleware(err, req, res, next) { if (err instanceof ApiError) { return res.status(err.httpStatus).json({ code: err.code, message: err.message, data: null }); } const HTTP_TO_CODE = { 400: 1001, 401: 1002, 403: 1003, 404: 1004, 409: 1005 }; if (err && typeof err.status === 'number') { return res.status(err.status).json({ code: HTTP_TO_CODE[err.status] || API_CODES.SERVER_ERROR, message: err.message || '请求错误', data: null, }); } console.error('[error]', err && err.stack ? err.stack : err); const detail = err?.sqlMessage || err?.message; return res.status(500).json({ code: API_CODES.SERVER_ERROR, message: detail ? `服务器错误:${detail}` : '服务器错误', data: null, }); } module.exports = { sanitize, ok, asyncHandler, errorMiddleware };