重构后端,完善获取资源/下载列表、博客列表接口

This commit is contained in:
2024-08-29 21:59:55 +08:00
parent 2a005b2e14
commit bc99fba385
18 changed files with 486 additions and 193 deletions

View File

@@ -0,0 +1,16 @@
import Logger from "../Logger";
abstract class API {
protected logger: Logger;
public middlewareFunc: Function[] = [];
constructor(public method: string, public uri: string, ...func: any) {
this.logger = new Logger('API][' + method + '][' + uri);
this.middlewareFunc.push(...func);
}
// to override
public abstract onRequset(data: any, res: any): void;
}
export { API };

View File

@@ -0,0 +1,53 @@
import express, { NextFunction, Request, Response } from "express";
import cors from "cors";
import Logger from "../Logger";
import { API } from "./API";
import ServerStdResponse from "../../ServerStdResponse";
class APILoader {
private app = express();
private logger = new Logger('APILoader');
constructor(private port?: number) {
this.logger.info('API服务加载中...');
this.app.use(express.json({ limit: '50mb' }));
this.app.use(express.urlencoded({ extended: true }));
this.app.use(cors({
origin: ['http://localhost:5173', 'http://note.ctbu.net.cn', 'http://124.223.5.195:23501'],
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization', 'Access-Control-Allow-Origin', ''],
}));
}
add(api: { new(): API }) {
const instance = new api();
for (let func of instance.middlewareFunc) {
this.app[instance.method.toLowerCase() as keyof express.Application](instance.uri, (req: Request, res: Response, next: NextFunction) => {
func(req, res, next);
});
this.logger.info(`[${instance.method}][${instance.uri}] 已启用中间件[${func.name}]`);
}
this.app[instance.method.toLowerCase() as keyof express.Application](instance.uri, (req: Request, res: Response) => {
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
this.logger.info(`[${instance.method}][${instance.uri}] 被请求[${(ip as string).replace('::ffff:', '')}]`);
const data = Object.assign({}, req.query, req.body);
instance.onRequset(data, res);
});
this.logger.info(`[${instance.method}][${instance.uri}] 加载成功`);
}
start(port?: number) {
if (this.port == undefined && port == undefined)
throw new Error('未指定API端口')
this.app.use((req: Request, res: Response) => {
this.logger.info(`[${req.method}][${req.url.split('?')[0]}] 该API不存在`);
res.json(ServerStdResponse.API_NOT_FOUND)
})
this.app.listen(port || this.port, () => {
this.logger.info(`已全部加载完成API服务开放在端口${port || this.port}`);
});
}
}
export {
APILoader,
}

View File

@@ -0,0 +1,40 @@
class Logger {
constructor(private namespace: string) {
}
private getTime(): string {
return new Date().toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' });
}
public info(info: string, ...args: any): void {
args = args.map((arg: any) => {
if (typeof arg === 'object') {
return JSON.stringify(arg);
}
return arg;
})
console.log(`[${this.getTime()}][INFO][${this.namespace}]${info[0] == '[' ? '' : ' '}${info} ` + args.join(' '));
}
public warn(info: string, ...args: any): void {
args = args.map((arg: any) => {
if (typeof arg === 'object') {
return JSON.stringify(arg);
}
return arg;
})
console.log(`[${this.getTime()}][WARN][${this.namespace}]${info[0] == '[' ? '' : ' '}${info} ` + args.join(' '));
}
public error(info: string, ...args: any): void {
args = args.map((arg: any) => {
if (typeof arg === 'object') {
return JSON.stringify(arg);
}
return arg;
})
console.log(`[${this.getTime()}][ERROR][${this.namespace}]${info[0] == '[' ? '' : ' '}${info} ` + args.join(' '));
}
}
export default Logger;

View File

@@ -0,0 +1,17 @@
import { Request, Response, NextFunction } from "express";
import config from "../../config";
import ServerStdResponse from "../../ServerStdResponse";
import Logger from "../Logger";
const logger = new Logger("Auth");
const Auth = (req: Request, res: Response, next: NextFunction) => {
let token = req.headers.authorization;
if (token === config.authToken || token == config.adminToken) {
next();
} else {
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
logger.info(`API[${req.method}][${req.url.split('?')[0]}] 请求鉴权不通过[${token}][${ip}]`);
res.json(ServerStdResponse.AUTH_ERROR);
}
}
export default Auth;

View File

@@ -0,0 +1,17 @@
import { Request, Response, NextFunction } from "express";
import config from "../../config";
import ServerStdResponse from "../../ServerStdResponse";
import Logger from "../Logger";
const logger = new Logger("AuthAdmin");
const AuthAdmin = (req: Request, res: Response, next: NextFunction) => {
let token = req.headers.authorization;
if (token === config.adminToken) {
next();
} else {
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
logger.info(`API[${req.method}][${req.url.split('?')[0]}] 请求鉴权不通过[${token}][${ip}]`);
res.json(ServerStdResponse.AUTH_ERROR);
}
}
export default AuthAdmin;

View File

@@ -0,0 +1,9 @@
import { Request, Response, NextFunction } from "express";
import Logger from "../Logger";
const logger = new Logger("Unbind");
const Unbind = (req: Request, res: Response, next: NextFunction) => {
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
logger.info(`API[${req.method}][${req.url.split('?')[0]}] 请求了未绑定的接口[${ip}]`);
}
export default Unbind;

View File

@@ -0,0 +1,77 @@
// MYSQL数据库连接池
// 版本v0.1
import mysql from "mysql2/promise";
import Logger from "./Logger";
import config from "../config";
class MySQLConnectPool {
private pool: any;
private logger = new Logger('MySQLConnection');
constructor() {
this.pool = this.createConnectPool();
this.logger.info("[MySQL] 数据库连接池已创建")
setTimeout(async () => {
let res = await this.testConnection();
if (res)
this.logger.info("[MySQL] 数据库测试成功")
else
this.logger.error("[MySQL] 数据库测试失败")
}, 10);
}
// 内部函数,无需手动调用
createConnectPool() {
return mysql.createPool({
host: config.mysql.host,
database: config.mysql.database,
user: config.mysql.user,
password: config.mysql.password,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
}
// 内部函数,无需手动调用
async testConnection() {
try {
let res = await this.execute("SELECT 1 + 1 As result");
if (res[0].result == 2)
return 1;
else
return 0;
} catch (error) {
this.logger.error(`[MySQL] 数据库测试发生了错误:` + error);
return 0;
}
}
// 执行SQL语句
async execute(sql: string, values?: any[], database?: string) {
let connection: any;
try {
connection = await this.pool.getConnection();
// 如果指定了数据库,则更改当前连接的数据库
if (database) {
await connection.changeUser({ database });
}
let [rows, fields] = await connection.execute(sql, values);
return rows;
} catch (error) {
this.logger.error("[MySQL] 数据库发生错误:" + error, '\n##', sql, '\n##', JSON.stringify(values));
return undefined;
} finally {
if (database)
await connection.changeUser({ database: config.mysql.database });// 恢复默认数据库
if (connection)
connection.release();
}
}
}
let MySQLConnection = new MySQLConnectPool();
export default MySQLConnection;