统一端口设置,可以设置自义定端口
This commit is contained in:
+82
-62
@@ -23,20 +23,21 @@ const proxyConfig = require('./config');
|
||||
// 自定义日志中间件
|
||||
function customLogger(req, res, next) {
|
||||
// 过滤掉静态资源请求和图片代理请求
|
||||
const isStaticResource = req.path.startsWith('/assets/') ||
|
||||
req.path.startsWith('/downloads/') ||
|
||||
req.path.includes('.js') ||
|
||||
req.path.includes('.css') ||
|
||||
req.path.includes('.ico') ||
|
||||
req.path.includes('.png') ||
|
||||
req.path.includes('.jpg') ||
|
||||
req.path.includes('.jpeg') ||
|
||||
req.path.includes('.gif') ||
|
||||
req.path.includes('.svg') ||
|
||||
req.path.includes('.woff') ||
|
||||
req.path.includes('.woff2') ||
|
||||
req.path.includes('.ttf') ||
|
||||
req.path.includes('.eot');
|
||||
const isStaticResource =
|
||||
req.path.startsWith('/assets/') ||
|
||||
req.path.startsWith('/downloads/') ||
|
||||
req.path.includes('.js') ||
|
||||
req.path.includes('.css') ||
|
||||
req.path.includes('.ico') ||
|
||||
req.path.includes('.png') ||
|
||||
req.path.includes('.jpg') ||
|
||||
req.path.includes('.jpeg') ||
|
||||
req.path.includes('.gif') ||
|
||||
req.path.includes('.svg') ||
|
||||
req.path.includes('.woff') ||
|
||||
req.path.includes('.woff2') ||
|
||||
req.path.includes('.ttf') ||
|
||||
req.path.includes('.eot');
|
||||
|
||||
// 过滤掉图片代理请求
|
||||
const isImageProxy = req.path === '/api/proxy/image';
|
||||
@@ -44,17 +45,17 @@ function customLogger(req, res, next) {
|
||||
// 只记录API请求和重要请求,排除静态资源和图片代理
|
||||
if (!isStaticResource && !isImageProxy) {
|
||||
const start = Date.now();
|
||||
|
||||
|
||||
// 原始响应结束方法
|
||||
const originalEnd = res.end;
|
||||
|
||||
|
||||
// 重写响应结束方法以获取响应时间
|
||||
res.end = function(chunk, encoding) {
|
||||
res.end = function (chunk, encoding) {
|
||||
const duration = Date.now() - start;
|
||||
const statusCode = res.statusCode;
|
||||
const method = req.method;
|
||||
const url = req.originalUrl;
|
||||
|
||||
|
||||
// 根据状态码选择颜色和图标
|
||||
let statusIcon, statusColor;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
@@ -70,38 +71,49 @@ function customLogger(req, res, next) {
|
||||
statusIcon = '❌';
|
||||
statusColor = '\x1b[31m'; // 红色
|
||||
}
|
||||
|
||||
|
||||
// 根据请求类型选择图标
|
||||
let methodIcon;
|
||||
switch (method) {
|
||||
case 'GET': methodIcon = '📥'; break;
|
||||
case 'POST': methodIcon = '📤'; break;
|
||||
case 'PUT': methodIcon = '🔄'; break;
|
||||
case 'DELETE': methodIcon = '🗑️'; break;
|
||||
case 'PATCH': methodIcon = '🔧'; break;
|
||||
default: methodIcon = '❓';
|
||||
case 'GET':
|
||||
methodIcon = '📥';
|
||||
break;
|
||||
case 'POST':
|
||||
methodIcon = '📤';
|
||||
break;
|
||||
case 'PUT':
|
||||
methodIcon = '🔄';
|
||||
break;
|
||||
case 'DELETE':
|
||||
methodIcon = '🗑️';
|
||||
break;
|
||||
case 'PATCH':
|
||||
methodIcon = '🔧';
|
||||
break;
|
||||
default:
|
||||
methodIcon = '❓';
|
||||
}
|
||||
|
||||
|
||||
// 格式化时间
|
||||
const now = new Date();
|
||||
const timeStr = now.toLocaleTimeString('zh-CN', {
|
||||
const timeStr = now.toLocaleTimeString('zh-CN', {
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
second: '2-digit',
|
||||
});
|
||||
|
||||
|
||||
// 构建日志消息
|
||||
const logMessage = `${statusColor}${statusIcon} ${methodIcon} ${method} ${url} ${statusCode} ${duration}ms\x1b[0m`;
|
||||
|
||||
|
||||
// 输出日志
|
||||
console.log(`[${timeStr}] ${logMessage}`);
|
||||
|
||||
|
||||
// 调用原始的end方法
|
||||
originalEnd.call(this, chunk, encoding);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
@@ -109,7 +121,7 @@ class PixivServer {
|
||||
constructor() {
|
||||
this.app = express();
|
||||
this.backend = null;
|
||||
this.port = process.env.PORT || 3000;
|
||||
this.port = 3000; // 默认端口,会在init时重新设置
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,23 +129,26 @@ class PixivServer {
|
||||
*/
|
||||
async init() {
|
||||
console.log('\x1b[34m🔧 正在初始化 Pixiv 后端服务器...\x1b[0m');
|
||||
|
||||
|
||||
// 重新设置端口(从环境变量获取)
|
||||
this.port = process.env.PORT || 3000;
|
||||
|
||||
// 设置代理
|
||||
proxyConfig.setEnvironmentVariables();
|
||||
|
||||
|
||||
// 初始化 Pixiv 后端
|
||||
this.backend = new PixivBackend();
|
||||
await this.backend.init();
|
||||
|
||||
|
||||
// 配置中间件
|
||||
this.setupMiddleware();
|
||||
|
||||
|
||||
// 配置路由
|
||||
this.setupRoutes();
|
||||
|
||||
|
||||
// 配置错误处理 - 临时注释掉
|
||||
this.setupErrorHandling();
|
||||
|
||||
|
||||
console.log('\x1b[32m✅ 服务器初始化完成\x1b[0m');
|
||||
}
|
||||
|
||||
@@ -143,23 +158,25 @@ class PixivServer {
|
||||
setupMiddleware() {
|
||||
// 自定义日志中间件(替换morgan)
|
||||
this.app.use(customLogger);
|
||||
|
||||
|
||||
// CORS 中间件
|
||||
this.app.use(cors({
|
||||
origin: process.env.FRONTEND_URL || 'http://localhost:5173',
|
||||
credentials: true
|
||||
}));
|
||||
|
||||
this.app.use(
|
||||
cors({
|
||||
origin: process.env.FRONTEND_URL || true, // 允许所有来源,或者通过环境变量指定
|
||||
credentials: true,
|
||||
})
|
||||
);
|
||||
|
||||
// JSON 解析中间件
|
||||
this.app.use(express.json({ limit: '10mb' }));
|
||||
this.app.use(express.urlencoded({ extended: true, limit: '10mb' }));
|
||||
|
||||
|
||||
// 静态文件服务
|
||||
this.app.use('/downloads', express.static(path.join(__dirname, '../downloads')));
|
||||
|
||||
|
||||
// 前端静态文件服务
|
||||
this.app.use(express.static(path.join(__dirname, '../ui/dist')));
|
||||
|
||||
|
||||
// 将后端实例注入到请求对象中
|
||||
this.app.use((req, res, next) => {
|
||||
req.backend = this.backend;
|
||||
@@ -173,13 +190,13 @@ class PixivServer {
|
||||
setupRoutes() {
|
||||
// 健康检查
|
||||
this.app.get('/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'ok',
|
||||
res.json({
|
||||
status: 'ok',
|
||||
timestamp: new Date().toISOString(),
|
||||
backend: {
|
||||
isLoggedIn: req.backend.isLoggedIn,
|
||||
user: req.backend.config.user?.account
|
||||
}
|
||||
user: req.backend.config.user?.account,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -191,17 +208,17 @@ class PixivServer {
|
||||
this.app.use('/api/ranking', authMiddleware, rankingRoutes);
|
||||
this.app.use('/api/repository', repositoryRoutes); // 仓库管理,不需要认证
|
||||
this.app.use('/api/proxy', proxyRoutes); // 图片代理,不需要认证
|
||||
|
||||
|
||||
// 404 处理
|
||||
this.app.use((req, res) => {
|
||||
// 如果是API请求,返回JSON格式的404
|
||||
if (req.path.startsWith('/api/')) {
|
||||
return res.status(404).json({
|
||||
error: 'Not Found',
|
||||
message: `Route ${req.originalUrl} not found`
|
||||
});
|
||||
return res.status(404).json({
|
||||
error: 'Not Found',
|
||||
message: `Route ${req.originalUrl} not found`,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 否则返回前端页面(SPA路由支持)
|
||||
res.sendFile(path.join(__dirname, '../ui/dist/index.html'));
|
||||
});
|
||||
@@ -245,13 +262,16 @@ class PixivServer {
|
||||
// 如果直接运行此文件
|
||||
if (require.main === module) {
|
||||
const server = new PixivServer();
|
||||
|
||||
|
||||
// 处理进程信号
|
||||
process.on('SIGINT', () => server.shutdown());
|
||||
process.on('SIGTERM', () => server.shutdown());
|
||||
|
||||
|
||||
// 启动服务器
|
||||
server.init().then(() => server.start()).catch(console.error);
|
||||
server
|
||||
.init()
|
||||
.then(() => server.start())
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = PixivServer;
|
||||
module.exports = PixivServer;
|
||||
|
||||
+38
-8
@@ -10,15 +10,38 @@ const PixivServer = require('./server');
|
||||
function parseArguments() {
|
||||
const args = process.argv.slice(2);
|
||||
const options = {};
|
||||
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const arg = args[i];
|
||||
if (arg === '--proxy-port' && i + 1 < args.length) {
|
||||
options.proxyPort = parseInt(args[i + 1]);
|
||||
|
||||
// 处理 --key=value 格式
|
||||
if (arg.startsWith('--proxy-port=')) {
|
||||
const port = parseInt(arg.split('=')[1]);
|
||||
if (!isNaN(port)) {
|
||||
options.proxyPort = port;
|
||||
}
|
||||
} else if (arg.startsWith('--server-port=')) {
|
||||
const port = parseInt(arg.split('=')[1]);
|
||||
if (!isNaN(port)) {
|
||||
options.serverPort = port;
|
||||
}
|
||||
}
|
||||
// 处理 --key value 格式(向后兼容)
|
||||
else if (arg === '--proxy-port' && i + 1 < args.length) {
|
||||
const port = parseInt(args[i + 1]);
|
||||
if (!isNaN(port)) {
|
||||
options.proxyPort = port;
|
||||
}
|
||||
i++; // 跳过下一个参数
|
||||
} else if (arg === '--server-port' && i + 1 < args.length) {
|
||||
const port = parseInt(args[i + 1]);
|
||||
if (!isNaN(port)) {
|
||||
options.serverPort = port;
|
||||
}
|
||||
i++; // 跳过下一个参数
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -34,6 +57,12 @@ if (cliOptions.proxyPort) {
|
||||
console.log(`\x1b[36m📡 代理端口已设置为: ${cliOptions.proxyPort}\x1b[0m`);
|
||||
}
|
||||
|
||||
// 如果提供了服务器端口,设置环境变量
|
||||
if (cliOptions.serverPort) {
|
||||
process.env.PORT = cliOptions.serverPort.toString();
|
||||
console.log(`\x1b[36m🌐 服务器端口已设置为: ${cliOptions.serverPort}\x1b[0m`);
|
||||
}
|
||||
|
||||
console.log('\x1b[35m🚀 启动 Pixiv 后端服务器...\x1b[0m');
|
||||
|
||||
// 创建服务器实例
|
||||
@@ -51,7 +80,7 @@ process.on('SIGTERM', async () => {
|
||||
});
|
||||
|
||||
// 处理未捕获的异常
|
||||
process.on('uncaughtException', (error) => {
|
||||
process.on('uncaughtException', error => {
|
||||
console.error('\x1b[31m❌ 未捕获的异常:\x1b[0m', error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -62,9 +91,10 @@ process.on('unhandledRejection', (reason, promise) => {
|
||||
});
|
||||
|
||||
// 启动服务器
|
||||
server.init()
|
||||
server
|
||||
.init()
|
||||
.then(() => server.start())
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
console.error('\x1b[31m❌ 服务器启动失败:\x1b[0m', error);
|
||||
process.exit(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user