Workers 与 Pages 是 Cloudflare 所提供的构建和部署网站的两种不同服务。我们可以通过在上面部署各种应用或 js 脚本来实现不同功能。
但在实际使用中,可能会部署多个 Pages 项目,此时如果要记住每个项目的域名或名称就会显得十分麻烦,不利于管理和访问,还会占用 DNS 记录的数量。此种状况下将所有项目整合到一个域名下,通过不同路径进行访问就显得尤为重要了。本文将介绍如何通过 Cloudflare Workers 实现单域名对多个 Pages 项目的访问。


前提条件

假设我们有两个 Pages 项目,分别是 project1(后文称其为 P1)和 project2(后文称其为 P2)。它们分别有两个默认域名 p1.pages.devp2.pages.dev。我们希望通过一个自定义域名 example.com 来访问它们。具体路径为 /p1/ 访问 P1/p2/ 访问 P2

创建 Workers

登录 Cloudflare 仪表盘 在左侧边栏位置依次点击 计算 (Workers) -> Workers 和 Pages 进入 Workers 页面。
点击创建按钮,在弹出的菜单中选择Workers从 Hello World! 开始 选项。忽略 Cloudflare 给出的初始代码,直接点击部署
创建一个Workers

转发原理

通过 Workers 实现单对多根本原理是在边缘平台监听请求路径,经判断后将请求转发到目标服务器中。

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
export default {
async fetch(request, env) {
try {
const url = new URL(request.url);
let targetUrl;

// 判断请求路径并转发至对应服务器
if (url.pathname.startsWith('p1')) {
// 去除路径中的 /p1 前缀
const newPath = url.pathname.replace('/p1', '') || '/';
targetUrl = `https://p1.pages.dev${newPath}${url.search}`;
} else if (url.pathname.startsWith('/p2')) {
// 去除路径中的 /p2 前缀
const newPath = url.pathname.replace('/p2', '') || '/';
targetUrl = `https://p2.pages.dev${newPath}${url.search}`;
} else {
targetUrl = `https://default.pages.dev${url.pathname}${url.search}`;
}

// 创建新的请求对象并转发
const newRequest = new Request(targetUrl, {
method: request.method,
headers: request.headers,
body: request.body,
redirect: 'follow'
});

const response = await fetch(newRequest);

// 设置headers
const newHeaders = new Headers(response.headers);
newHeaders.set('Access-Control-Allow-Origin', '*');

return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHeaders
});

} catch (e) {
return new Response(`路由处理错误: ${e.message}`, { status: 500 });
}
}
};

将代码中的 p1.pages.devp2.pages.dev 替换为你的 Pages 项目的实际域名,/p1 /p2 替换为实际需求路径。保存并部署代码。
可以注意到在 else 分支中存在一个 default.pages.dev 域名。也就是说你可以链接一个中转网页(也可以直接返回 HTML 页面),方便在访问根目录时进行选择。只需在要添加的位置中使用元素 a

1
<a href="/p1/">访问项目1</a>

即可实现从中转页面跳转至其他项目。

由于代码仅是对请求做了转发,删去了路径前缀,但前端代码(如HTML对绝对路径的引用)仍然会尝试访问原先的路径,造成 404 Not Found 错误。此时应在其余项目中的index.html添加下文中的 JavaScript 代码解决问题

1
2
3
4
const path = window.location.pathname.replace(/index\.html$/, '');
const baseHref = path.endsWith('/') ? path : `${path}/`;
console.log('Base path set to:', baseHref);
document.write(`<base href="${baseHref}" />`);

这段代码能够动态设置<base>标签,确保所有相对路径引用都基于当前路径,从而避免 404 错误。

添加自定义域名

在路由项目的 Workers 页面点击 设置 按钮,在 域和路由 选项卡中点击 + 添加 按钮,点击 自定义域,键入你的域名 project.example.com添加即可。
添加自定义域名

常见问题

  1. 为什么访问时会出现 404 Not Found?

    • 上文正确设置基准路径
  2. 如何处理跨域问题?

    • 代码中已添加Access-Control-Allow-Origin头,允许所有来源访问。如果有更严格的需求,可以根据实际情况修改。
  3. 如何添加更多的 Pages 项目?

    • 只需在fetch函数中添加更多的else if分支,按照相同的逻辑进行路径判断和转发即可。
  4. 转发有限制吗

    • Workers 有一定的免费额度(100,000 次 / 天),超过后会产生费用,在日常使用中绝对够用。具体请参考 Cloudflare 的定价页面