File size: 4,837 Bytes
018314f
 
 
 
 
 
 
 
 
 
 
6279ff0
 
 
 
 
6acb2cb
 
6279ff0
 
 
 
018314f
1e6a865
 
6279ff0
 
6acb2cb
6279ff0
6acb2cb
6279ff0
 
 
 
6acb2cb
 
6279ff0
6acb2cb
 
6279ff0
 
6acb2cb
 
 
6279ff0
6acb2cb
 
6279ff0
6acb2cb
6279ff0
6acb2cb
6279ff0
 
 
 
 
 
 
6acb2cb
6279ff0
 
 
 
1e6a865
 
018314f
1e6a865
 
6acb2cb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6279ff0
6acb2cb
 
6279ff0
6acb2cb
6279ff0
6acb2cb
6279ff0
 
6acb2cb
6279ff0
6acb2cb
6279ff0
 
6acb2cb
 
 
6279ff0
6acb2cb
 
1e6a865
6acb2cb
 
 
6279ff0
 
6acb2cb
6279ff0
6acb2cb
6279ff0
6acb2cb
 
 
 
 
6279ff0
 
6acb2cb
 
6279ff0
 
6acb2cb
6279ff0
 
6acb2cb
6279ff0
 
 
 
 
 
 
6acb2cb
6279ff0
 
 
1e6a865
 
018314f
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
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;
const HOST = '0.0.0.0';
console.log(`Starting server! 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 = 90 * 1000; // 90 秒
const CLEANUP_INTERVAL = 60 * 1000; // 每 60 秒清理一次

// 定时清理过期数据
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 healthy and running!" });
});

// === 辅助函数 ===
// 生成设备指纹
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 starting server: ${err}`);
        return;
    }
    console.log(`Server running on http://${HOST}:${PORT}`);
});


console.log("Environment Variables:", process.env);