File size: 3,897 Bytes
0133533 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
import express from 'express'
import { getPort } from './configs/config.js'
import router from './routes/routes.js'
const app = express();
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ extended: true, limit: '50mb' }));
// 生成请求ID (UUID格式)
function generateRequestId() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0
const v = c === 'x' ? r : (r & 0x3 | 0x8)
return v.toString(16)
})
}
// 获取客户端IP
function getClientIp(req) {
return req.headers['x-forwarded-for']?.split(',')[0].trim() ||
req.headers['x-real-ip'] ||
req.connection?.remoteAddress ||
req.socket?.remoteAddress ||
'unknown'
}
// 请求日志中间件
app.use((req, res, next) => {
const startTime = Date.now()
const requestId = generateRequestId()
const clientIp = getClientIp(req)
// 将请求ID附加到req对象
req.requestId = requestId
// 请求开始时打印日志
console.log(`[INFO] [${requestId}] [${clientIp}] ${req.method} ${req.path}`)
// 保存原始的 res.json 和 res.end 方法
const originalJson = res.json.bind(res)
const originalEnd = res.end.bind(res)
// 重写 res.json 方法以捕获响应状态
res.json = function(data) {
logRequestEnd(req, res, startTime, requestId, clientIp)
return originalJson(data)
}
// 重写 res.end 方法以捕获流式响应状态
res.end = function(...args) {
logRequestEnd(req, res, startTime, requestId, clientIp)
return originalEnd(...args)
}
next()
})
// 请求结束日志记录函数
function logRequestEnd(req, res, startTime, requestId, clientIp) {
// 避免重复记录
if (res._logged) return
res._logged = true
const duration = ((Date.now() - startTime) / 1000).toFixed(3)
const status = res.statusCode
console.log(`[INFO] [${requestId}] [${clientIp}] 响应状态: ${status}`)
console.log(`[INFO] [${requestId}] [${clientIp}] 处理时间: ${duration}s`)
}
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Key, anthropic-version');
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
app.use(router);
app.get('/', (req, res) => {
res.redirect('https://www.bilibili.com/video/BV1SMH5zfEwe/?spm_id_from=333.1007.tianma.1-1-1.click&vd_source=1f3b8eb28230105c578a443fa6481550')
})
// 错误处理中间件
app.use((err, req, res, next) => {
console.error('未处理的错误:', err);
res.status(500).json({
error: '内部服务器错误',
message: err.message
});
});
(async () => {
try {
const PORT = getPort()
app.listen(PORT)
.on('listening', () => {
console.log(`服务器运行在 http://localhost:${PORT}`)
})
.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
console.error(`\n${'='.repeat(80)}`);
console.error(`错误: 端口 ${PORT} 已被占用!`);
console.error('');
console.error('请选择以下选项之一:');
console.error(` 1. 停止使用端口 ${PORT} 的进程:`);
console.error(` lsof -ti:${PORT} | xargs kill`);
console.error('');
console.error(' 2. 使用环境变量更改端口:');
console.error(' export PORT=8080');
console.error(`${'='.repeat(80)}\n`);
process.exit(1);
} else {
console.error('启动服务器失败:', err);
process.exit(1);
}
});
} catch (error) {
console.error('启动服务器失败:', error);
process.exit(1);
}
})();
|