url_server / server.js
CatPtain's picture
Update server.js
3f54b86 verified
// === 全局异常处理(放在顶部) ===
process.on('uncaughtException', (err) => {
console.error('[Fatal Error] Uncaught Exception:', err.stack || err.message || err);
process.exit(1); // 可选择退出服务进程
});
process.on('unhandledRejection', (reason, promise) => {
console.error('[Warning] Unhandled Rejection at:', promise, 'reason:', reason);
});
// === 引入依赖 ===
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const requestIp = require('request-ip');
const crypto = require('crypto'); // 用于生成设备指纹的哈希值
const { URL } = require('url'); // 用于验证 URL 格式
const app = express();
// === 配置常量 ===
const PORT = process.env.PORT || 7860; // 动态分配的端口
const HOST = '0.0.0.0';
// 检查 PORT 是否有效
if (!PORT) {
console.error("[Error] PORT environment variable is undefined. This is required by Hugging Face Spaces.");
process.exit(1); // 如果 PORT 未定义,立即退出
}
console.log(`Starting server with HOST: ${HOST}, PORT: ${PORT}`);
// === 中间件配置 ===
// CORS 配置
const corsOptions = {
origin: '*', // 允许所有来源的请求
methods: ['GET', 'POST', 'OPTIONS'],
allowedHeaders: ['Content-Type'],
};
app.use(cors(corsOptions));
// 使用 Body-Parser 解析 JSON 请求体
app.use(bodyParser.json());
// 使用 request-ip 中间件获取客户端 IP
app.use(requestIp.mw());
// === 内存存储及清理 ===
// URL 存储字典(以用户唯一标识符为键)
const urlMap = new Map();
// 超时时间配置(以毫秒为单位)
const EXPIRATION_TIME = 5 * 60 * 1000; // 数据保存5分钟
const CLEANUP_INTERVAL = 5.1 * 60 * 1000; // 每 5分6 秒清理一次
// 定时清理过期数据
setInterval(() => {
const now = Date.now();
const expiredTime = now - EXPIRATION_TIME;
for (const [userId, { timestamp }] of urlMap) {
if (timestamp < expiredTime) {
console.log(`Deleting expired data for user: ${userId}`);
urlMap.delete(userId); // 删除过期数据
}
}
}, CLEANUP_INTERVAL);
// 健康检查路由
app.get('/', (req, res) => {
res.status(200).json({
message: "Server is running with backup port.",
port: PORT || "undefined",
environment: process.env,
});
});
// === 辅助函数 ===
// 生成设备指纹
const generateDeviceFingerprint = (req) => {
const ip = req.clientIp || '';
const userAgent = req.headers['user-agent'] || '';
const acceptLanguage = req.headers['accept-language'] || '';
const connection = req.headers['connection'] || '';
const encoding = req.headers['accept-encoding'] || '';
const forwardedFor = req.headers['x-forwarded-for'] || '';
// 将关键信息合并生成唯一指纹
const rawFingerprint = `${ip}-${userAgent}-${acceptLanguage}-${connection}-${encoding}-${forwardedFor}`;
// 使用 SHA-256 哈希算法生成指纹
const fingerprint = crypto.createHash('sha256').update(rawFingerprint).digest('hex');
return fingerprint;
};
// === 路由与业务逻辑 ===
// 存储 URL(POST 请求)
app.post('/storeURL', (req, res) => {
const url = req.body.url; // 从请求体中解析 URL
const ip = req.clientIp; // 获取客户端 IP
// 验证 URL 是否存在并合法
if (!url) {
return res.status(400).json({ error: 'URL is required.' });
}
try {
new URL(url); // 验证 URL 格式
} catch (err) {
return res.status(400).json({ error: 'Invalid URL format.' });
}
// 生成用户唯一标识符(包括 IP 和设备指纹)
const deviceFingerprint = generateDeviceFingerprint(req);
const userId = `${ip}-${deviceFingerprint}`; // 结合 IP 和设备指纹生成唯一标识符
// 存储到字典中
urlMap.set(userId, { url, timestamp: Date.now() });
console.log(`Stored URL for user: ${userId}`);
// 返回成功响应
res.json({ message: 'URL stored successfully.', userId });
});
// 获取 URL(GET 请求)
app.get('/getURL', (req, res) => {
const ip = req.clientIp; // 获取客户端 IP
// 生成用户唯一标识符(包括 IP 和设备指纹)
const deviceFingerprint = generateDeviceFingerprint(req);
const userId = `${ip}-${deviceFingerprint}`;
// 查询字典获取存储的 URL
if (urlMap.has(userId)) {
const storedData = urlMap.get(userId);
storedData.timestamp = Date.now(); // 更新数据时间戳
urlMap.set(userId, storedData); // 保存更新后的数据
console.log(`Retrieved URL for user: ${userId}`);
return res.json({ url: storedData.url });
} else {
console.error(`No URL found for user: ${userId}`);
return res.status(404).json({ error: 'URL not found for this user.' });
}
});
// === 启动服务器 ===
app.listen(PORT, HOST, (err) => {
if (err) {
console.error("[Error] Server failed to start:", err);
process.exit(1); // 如果存在错误,立即退出
}
console.log(`Server successfully started on http://${HOST}:${PORT}`);
});
// 打印环境变量(调试使用)
console.log("Full Environment Variables:", process.env);