feat: add utils, error handler and auth middleware

This commit is contained in:
Developer
2026-03-18 16:03:38 +08:00
parent b0ce7dcbaf
commit 9c3281e6ac
3 changed files with 261 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
const jwt = require('jsonwebtoken');
const { AppError } = require('./errorHandler');
const JWT_SECRET = process.env.JWT_SECRET || 'accountbook_secret_key_2024';
function authenticate(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
throw new AppError('请先登录', 401, 'UNAUTHORIZED');
}
try {
const decoded = jwt.verify(token, JWT_SECRET);
req.userId = decoded.userId;
next();
} catch (err) {
throw new AppError('登录已过期', 401, 'TOKEN_EXPIRED');
}
}
function generateToken(userId) {
return jwt.sign({ userId }, JWT_SECRET, { expiresIn: '7d' });
}
module.exports = {
authenticate,
generateToken,
JWT_SECRET,
};
+62
View File
@@ -0,0 +1,62 @@
class AppError extends Error {
constructor(message, statusCode = 500, code = 'INTERNAL_ERROR') {
super(message);
this.statusCode = statusCode;
this.code = code;
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
function errorHandler(err, req, res, next) {
console.error({
message: err.message,
stack: err.stack,
url: req.url,
method: req.method,
userId: req.userId,
});
if (err instanceof AppError && err.isOperational) {
return res.status(err.statusCode).json({
error: err.message,
code: err.code,
});
}
// 数据库唯一性冲突
if (err.code === 'SQLITE_CONSTRAINT_UNIQUE') {
return res.status(400).json({
error: '数据已存在',
code: 'DUPLICATE_ENTRY',
});
}
// 其他数据库错误
if (err.code && err.code.startsWith('SQLITE_')) {
return res.status(500).json({
error: '数据库错误',
code: 'DATABASE_ERROR',
});
}
// 默认错误响应
res.status(500).json({
error: process.env.NODE_ENV === 'production'
? '服务器内部错误'
: err.message,
code: 'INTERNAL_ERROR',
});
}
function asyncHandler(fn) {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}
module.exports = {
AppError,
errorHandler,
asyncHandler,
};