Improvements

This commit is contained in:
jason5ng32 committed 2026-04-18 19:45:11 +08:00
1 parent ca4db706df
commit 57f03e66ec
10 files changed
+22 -22

No files matched your search

+3 -3
View File
@@ -1,4 +1,4 @@
# 第一阶段:构建 # Build stage
FROM node:24-alpine AS build-stage FROM node:24-alpine AS build-stage
WORKDIR /app WORKDIR /app
COPY package*.json ./ COPY package*.json ./
@@ -6,7 +6,7 @@ RUN npm install
COPY . . COPY . .
RUN npm run build RUN npm run build
# 第二阶段:运行 # Production stage
FROM node:24-alpine AS production-stage FROM node:24-alpine AS production-stage
WORKDIR /app WORKDIR /app
COPY --from=build-stage /app/node_modules ./node_modules COPY --from=build-stage /app/node_modules ./node_modules
@@ -19,5 +19,5 @@ COPY --from=build-stage /app/common ./common
EXPOSE 18966 EXPOSE 18966
# 启动应用 # Start application
CMD ["npm", "start"] CMD ["npm", "start"]
+13 -13
View File
@@ -49,7 +49,7 @@ const speedLimitSet = parseInt(process.env.SECURITY_DELAY_AFTER || 0, 10);
app.set('trust proxy', 1); app.set('trust proxy', 1);
// 获取客户端 IP 的辅助函数。 // Helper function to get client IP
function getClientIp(req) { function getClientIp(req) {
const cfIp = req.headers['cf-connecting-ip']; // Cloudflare IP const cfIp = req.headers['cf-connecting-ip']; // Cloudflare IP
const forwardedIps = req.headers['x-forwarded-for'] ? req.headers['x-forwarded-for'].split(',')[0] : null; const forwardedIps = req.headers['x-forwarded-for'] ? req.headers['x-forwarded-for'].split(',')[0] : null;
@@ -57,23 +57,23 @@ function getClientIp(req) {
return cfIp || forwardedIps || cfIpV6 || req.ip; return cfIp || forwardedIps || cfIpV6 || req.ip;
} }
// 将时间戳格式化为限流日志使用的上海时区时间。 // Format timestamp for rate limit log using Shanghai time zone
function formatDate(timestamp) { function formatDate(timestamp) {
return new Date(timestamp).toLocaleString('en-US', { timeZone: 'Asia/Shanghai' }); return new Date(timestamp).toLocaleString('en-US', { timeZone: 'Asia/Shanghai' });
} }
// 将触发限流的 IP 写入日志,并累计同一个 IP 被限制的次数。 // Write IP that triggered the limit to the log and count the number of times the same IP was limited
function logLimitedIP(ip) { function logLimitedIP(ip) {
const logPath = path.join(__dirname, blackListIPLogFilePath); const logPath = path.join(__dirname, blackListIPLogFilePath);
// 如果 logs 目录不存在,则创建 // If logs directory does not exist, create it
const logDir = path.dirname(logPath); const logDir = path.dirname(logPath);
if (!fs.existsSync(logDir)) { if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true }); fs.mkdirSync(logDir, { recursive: true });
console.log('Created log directory:', logDir); console.log('Created log directory:', logDir);
} }
// 读取日志文件,更新 IP 计数,如果文件不存在则创建新的日志文件 // Read log file, update IP count, create new log file if it does not exist
fs.readFile(logPath, 'utf8', (err, data) => { fs.readFile(logPath, 'utf8', (err, data) => {
if (err && err.code !== 'ENOENT') { if (err && err.code !== 'ENOENT') {
console.error('Error reading the log file:', err); console.error('Error reading the log file:', err);
@@ -117,7 +117,7 @@ const rateLimiter = rateLimit({
windowMs: 20 * 60 * 1000, windowMs: 20 * 60 * 1000,
max: rateLimitSet, max: rateLimitSet,
message: 'Too Many Requests', message: 'Too Many Requests',
// 处理超过限流阈值的请求,并按需记录触发限流的 IP。 // Handle requests that exceed the rate limit threshold, and record the IP that triggered the limit as needed
handler: (req, res, next) => { handler: (req, res, next) => {
const ip = getClientIp(req); const ip = getClientIp(req);
if (req.rateLimit.current === req.rateLimit.limit + 1 && blackListIPLogFilePath) { if (req.rateLimit.current === req.rateLimit.limit + 1 && blackListIPLogFilePath) {
@@ -130,17 +130,17 @@ const rateLimiter = rateLimit({
const speedLimiter = slowDown({ const speedLimiter = slowDown({
windowMs: 60 * 60 * 1000, windowMs: 60 * 60 * 1000,
delayAfter: speedLimitSet, delayAfter: speedLimitSet,
// 根据命中次数逐步增加响应延迟。 // Increase response delay gradually based on the number of hits
delayMs: (hits) => hits * 400, delayMs: (hits) => hits * 400,
}) })
// 如果 rateLimitSet 为 0,则不启用限流 // If rateLimitSet is 0, do not enable rate limiting
if (rateLimitSet !== 0) { if (rateLimitSet !== 0) {
app.use('/api', rateLimiter); app.use('/api', rateLimiter);
console.log('Rate limiter is enabled, limit:', rateLimitSet, 'requests per 60 minutes'); console.log('Rate limiter is enabled, limit:', rateLimitSet, 'requests per 60 minutes');
} }
// 如果 deleyAfter 为 0,则不启用延迟 // If delayAfter is 0, do not enable delay
if (speedLimitSet !== 0) { if (speedLimitSet !== 0) {
app.use('/api', speedLimiter); app.use('/api', speedLimiter);
console.log('Speed limiter is enabled, slowing down after:', speedLimitSet, 'requests'); console.log('Speed limiter is enabled, slowing down after:', speedLimitSet, 'requests');
@@ -170,17 +170,17 @@ app.get('/api/maxmind', requireValidIP(), maxmindHandler);
app.get('/api/getuserinfo', getUserinfo); app.get('/api/getuserinfo', getUserinfo);
app.put('/api/updateuserachievement', updateUserAchievement); app.put('/api/updateuserachievement', updateUserAchievement);
// 使用查询参数处理所有配置请求 // Handle all configuration requests using query parameters
app.get('/api/configs', validateConfigs); app.get('/api/configs', validateConfigs);
// 设置静态文件服务 // Set static file server
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
app.use(express.static(path.join(__dirname, './dist'))); app.use(express.static(path.join(__dirname, './dist')));
// 启动服务器 // Start server
app.listen(backEndPort, () => { app.listen(backEndPort, () => {
// 输出监听地址,便于本地运行和进程管理器日志排查。 // Output listening address, for local running and process manager log troubleshooting
console.log(`Backend server running on http://localhost:${backEndPort}`); console.log(`Backend server running on http://localhost:${backEndPort}`);
}); });
+3 -3
View File
@@ -4,8 +4,8 @@ services:
myip: myip:
container_name: myip container_name: myip
image: jason5ng32/myip:latest # my-app: x.x.x image: jason5ng32/myip:latest # my-app: x.x.x
stdin_open: true # docker run -i 交互模式 stdin_open: true # docker run -i interactive mode
tty: true # docker run -t 终端模式 tty: true # docker run -t terminal mode
restart: always # 重启策略 / on-failure:5 重启次数5次 / always 一直重启 / unless-stopped 除非停止 / no 从不重启 restart: always # restart policy / on-failure:5 restart 5 times / always restart forever / unless-stopped unless stopped / no never restart
ports: ports:
- "18966:18966" - "18966:18966"
+3 -3
View File
@@ -14,16 +14,16 @@ const frontEndPort = parseInt(process.env.FRONTEND_PORT || 18966, 10);
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
// API 请求代理到后端服务 // API Proxy to backend server
frontendApp.use('/api', createProxyMiddleware({ frontendApp.use('/api', createProxyMiddleware({
target: `http://localhost:${backEndPort}/api`, target: `http://localhost:${backEndPort}/api`,
changeOrigin: true changeOrigin: true
})); }));
// 设置静态文件目录 // Set static file directory
frontendApp.use(express.static(path.join(__dirname, './dist'))); frontendApp.use(express.static(path.join(__dirname, './dist')));
// 启动静态文件服务 // Start static file server
frontendApp.listen(frontEndPort, () => { frontendApp.listen(frontEndPort, () => {
console.log(`Static file server running on port http://localhost:${frontEndPort}`); console.log(`Static file server running on port http://localhost:${frontEndPort}`);
}); });
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 405 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 435 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 403 KiB