如何使用 Cloudflare Worker 实现延迟测试工具

如何使用 Cloudflare Worker 实现延迟测试工具

在这篇教程中,我们将学习如何使用 Cloudflare Worker 创建一个简单的延迟测试工具。这个工具可以测量多个 URL 的响应延迟,并根据结果重定向用户,同时在页面上显示每个 URL 的延迟信息,使用不同的颜色来指示延迟的高低。

准备工作

  1. 注册 Cloudflare 账户:如果你还没有 Cloudflare 账户,访问 Cloudflare 官网 注册一个账户。
  2. 创建一个新的 Worker:在 Cloudflare 的控制面板中,选择 “Workers” 并创建一个新的 Worker。

实现步骤

1. 事件监听

首先,我们需要设置一个事件监听器,来处理所有传入的请求。当请求到达时,我们将调用 handleRequest 函数。

1
2
3
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});

2. 构建 HTML 内容

handleRequest 函数中,我们将生成一个包含加载动画和结果显示区域的 HTML 页面。以下是 HTML 模板:

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
async function handleRequest(request) {
const htmlContent = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Latency Test</title>
<style>
body {
background: linear-gradient(135deg, #e2e2e2, #ffffff);
animation: backgroundAnimation 10s infinite alternate;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin: 0;
}
.loader {
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid #3498db;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#result {
display: none;
opacity: 0;
transition: opacity 0.5s;
text-align: center;
font-size: 20px;
color: #3498db;
}
@keyframes backgroundAnimation {
0% { background-color: #ffffff; }
100% { background-color: #f3f3f3; }
}
</style>
</head>
<body>
<div class="loader" id="loader"></div>
<div id="result"></div>
<script>
// JavaScript 代码
</script>
</body>
</html>`;

return new Response(htmlContent, {
headers: { 'Content-Type': 'text/html' },
});
}

加载动画示例:
加载动画示例

3. 测量延迟

创建一个名为 measureLatency 的函数,该函数将发送一个 HEAD 请求来测量 URL 的延迟。

1
2
3
4
5
6
7
8
9
10
async function measureLatency(url) {
const start = Date.now();
try {
await fetch(url, { method: 'HEAD' });
return Date.now() - start;
} catch (error) {
console.error('Error measuring latency:', error);
return Infinity; // Treat failures as the worst latency
}
}

4. 根据延迟重定向

testLatency 函数中,我们将调用 measureLatency 测量两个 URL 的延迟,并根据结果决定重定向到哪个 URL。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
async function testLatency() {
const cfPagesUrl = 'https://666.com';
const vercelUrl = 'https://888.com';

const cfPagesLatency = await measureLatency(cfPagesUrl);
const vercelLatency = await measureLatency(vercelUrl);

const resultElement = document.getElementById('result');
const loaderElement = document.getElementById('loader');

loaderElement.style.display = 'none';
resultElement.style.display = 'block';

let targetUrl;
if (cfPagesLatency < vercelLatency) {
resultElement.innerText = 'Redirecting to CF Pages...';
targetUrl = cfPagesUrl;
} else {
resultElement.innerText = 'Redirecting to Vercel...';
targetUrl = vercelUrl;
}
}

5. 显示延迟信息

动态更新结果区域,显示各个 URL 的延迟,并使用不同的颜色来指示延迟等级:

1
2
3
4
5
6
7
8
9
10
function getColorForLatency(latency) {
if (latency < 100) return 'green'; // 低延迟
else if (latency < 300) return 'orange'; // 中等延迟
else return 'red'; // 高延迟
}

// 显示各个 URL 的延迟
const cfPagesMessage = \`CF Pages 延迟: <span style="color:\${getColorForLatency(cfPagesLatency)};">\${cfPagesLatency} ms</span>\`;
const vercelMessage = \`Vercel 延迟: <span style="color:\${getColorForLatency(vercelLatency)};">\${vercelLatency} ms</span>\`;
resultElement.innerHTML += '<br>' + cfPagesMessage + '<br>' + vercelMessage;

结果动画示例:
结果动画示例

6. 完整代码 (2024-11-15优化了一下代码)

将所有部分结合在一起,以下是完整的 Cloudflare Worker 代码:

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
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
const htmlContent = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Latency Test</title>
<style>
body {
background: linear-gradient(135deg, #e2e2e2, #ffffff);
animation: backgroundAnimation 10s infinite alternate;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin: 0;
}

.loader {
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid #3498db;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
}

@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

#result {
display: none;
opacity: 0;
transition: opacity 0.5s;
text-align: center;
font-size: 20px;
color: #3498db;
}

@keyframes backgroundAnimation {
0% { background-color: #ffffff; }
100% { background-color: #f3f3f3; }
}
</style>
</head>
<body>
<div class="loader" id="loader"></div>
<div id="result"></div>
<script>
async function measureLatency(url, retries = 3) {
let latency = Infinity; // 初始化为最大值
for (let i = 0; i < retries; i++) {
const start = Date.now();
try {
await fetch(url, { method: 'HEAD' });
latency = Date.now() - start;
break; // 如果成功,跳出循环
} catch (error) {
console.warn(\`Retry \${i + 1} failed for \${url}\`);
}
}
return latency;
}

function getColorForLatency(latency) {
if (latency < 100) return 'green';
if (latency < 300) return 'orange';
return 'red';
}

async function testLatency() {
const urls = [
{ name: 'CF Pages', url: 'https://cf.666.com/' },
{ name: 'Vercel', url: 'https://vc.888.com/' },
{ name: 'GitHub', url: 'https://gh.666.com/' },
{ name: 'Netlify', url: 'https://nl.888.com/' },
{ name: '备用', url: 'https://blog.666.com/' }
];

const results = await Promise.all(
urls.map(async ({ name, url }) => {
const latency = await measureLatency(url);
return { name, url, latency };
})
);

results.sort((a, b) => a.latency - b.latency);

const resultElement = document.getElementById('result');
const loaderElement = document.getElementById('loader');

loaderElement.style.display = 'none';
resultElement.style.display = 'block';

results.forEach(({ name, latency }) => {
resultElement.innerHTML += \`\${name} 延迟: <span style="color:\${getColorForLatency(latency)};">\${latency} ms</span><br>\`;
});

const bestOption = results[0];
resultElement.innerHTML += '<br>Redirecting to ' + bestOption.name + '...';

setTimeout(() => {
resultElement.style.opacity = 1;
setTimeout(() => {
window.location.href = bestOption.url;
}, 2000);
}, 100);
}

window.onload = testLatency;
</script>
</body>
</html>`;

return new Response(htmlContent, {
headers: { 'Content-Type': 'text/html' },
});
}

运行和测试

如需要增加或修改 URL,只需要修改 urls 数组。如下面代码中,我们添加了两个 URL:

1
2
3
4
5
6
7
8
9
10
async function testLatency() {
const urls = [
{ name: 'CF Pages', url: 'https://cf.666.com/' },
{ name: 'Vercel', url: 'https://vc.888.com/' },
{ name: 'GitHub', url: 'https://gh.666.com/' },
{ name: 'Netlify', url: 'https://nl.888.com/' },
{ name: '备用', url: 'https://blog.666.com/' },
{ name: '新URL1', url: 'https://newurl1.com/' },
{ name: '新URL2', url: 'https://newurl2.com/' }
];

完成上述步骤后,保存并部署你的 Worker。打开分配给你的 Worker 的 URL,你应该能看到加载动画,随后页面将显示测量的延迟和重定向信息。

结语

通过本教程,你学会了如何使用 Cloudflare Worker 创建一个延迟测试工具。