使用 Cloudflare Workers 为 Bento.me 设置自定义域名

Bento.me 是一个零代码创建个人主页的平台,以优雅美观的界面和使用简单而闻名。

但它唯一的缺点是:不支持自定义域名

但别担心,本文将用最简单、零成本的方式,帮助你为 Bento.me 绑定自定义域名。

1. 提前准备

  1. 你需要有一个 Bento.me 个人页面
  2. 注册/准备一个 Cloudflare 账号
  3. 拥有独立域名,并将其转移至 Cloudflare 管理 DNS

2. 创建 cloudflare Worker 项目

在终端中输入以下命令,创建一个基础的 Cloudflare Worker:

npm create cloudflare@latest

终端操作

然后按照终端内说明进行操作:

  • In which directory do you want to create your application? 你现在哪个目录创建应用

    • 默认或者自定义都可
  • What type of application do you want to create? 你想创建什么类型的应用?

    • 选择 “Hello World” Worker 即可
  • Do you want to use TypeScript? 你想使用 TypeScript 吗?

    • 选择 NO(用键盘→选择)
  • Do you want to use git for version control? 你想使用 Git 进行版本控制吗?

    • 选择 Yes
  • Do you want to deploy your application? 你想部署应用么?

    • 选择 Yes(如果你第一次使用,会自动打开网页要求登录)

完成后对应目录会出现一个文件夹,使用 Visual Studio Code 等代码编辑工具打开这个文件夹。

3. 设置环境变量

  1. 编辑 wrangler.toml 文件,在末尾添加下列内容:
[vars]
BENTO_USERNAME = "len" # 替换为你的 Bento 页面 ID,我的是 bento.me/len
E_URL = "https://lenchou.com" # 替换为你的自定义域名
  1. 在文件夹根目录创建 .dev.vars 文件,黏贴下列内容:
BENTO_USERNAME="len" # 替换为你的 Bento 页面 ID
BASE_URL="http://127.0.0.1:8787"

4. 创建 Worker

  1. 编辑 /src/index.js 文件,替换为下列内容:

    /*
     * 为 Bento.me 设置自定义域名
     * 作者:len
     * 详情:https://imzl.com/bento-add-domain.html
     * 源代码来源:https://jayfranco.hashnode.dev/
     */
    
    // 事件监听
    addEventListener('fetch', event => {
      // 发生 fetch 事件时,用 handleRequest 函数结果做出响应
      event.respondWith(handleRequest(event.request));
    });
    
    // 根据内容类型解析响应
    async function parseResponseByContentType(response, contentType) {
      // 如果没有内容类型,响应以文本形式返回
      if (!contentType) return await response.text();
    
      // 根据内容类型不同,采取不同的操作
      switch (true) {
        case contentType.includes('application/json'):
          // 如果是 JSON,以 JSON 字符串形式返回
          return JSON.stringify(await response.json());
        case contentType.includes('text/html'):
          // 如果是 HTML,则使用 HTMLRewriter 对 response 进行转换
          const transformedResponse = new HTMLRewriter()
            .on('body', {
              element(element) {
                // 自定义 CSS 和 JS 可添加到 HTML 页面中
                element.append(
                  `
                    <style>
                      // 在这里输入你需要的自定义 CSS
                    </style>
                    `,
                  { html: true },
                );
                element.append(
                  `
                    <script>
                      // 在这里输入你需要的自定义 JS
                    </script>
                    `,
                  { html: true },
                );
              },
            })
            .transform(response);
          // 转换后的 response 以文本形式返回
          return await transformedResponse.text();
    
        case contentType.includes('font'):
          // 如果内容类型是字体,响应将以 ArrayBuffer 形式返回
          return await response.arrayBuffer();
    
        case contentType.includes('image'):
          // 如果内容类型是图片,响应将以 ArrayBuffer 形式返回
          return await response.arrayBuffer()
    
        default:
          // 如果内容类型是其他类型,响应将以文本形式返回
          return await response.text();
      }
    }
    
    // 处理所有请求的函数
    async function handleRequest(request) {
      // 从请求 URL 中提取路径
      const path = new URL(request.url).pathname;
      // 默认情况下,URL 设置为 "https://bento.me" + 路径
      let url = 'https://bento.me' + path;
    
      // 如果路径包含'v1',URL 将更改为 'https://api.bento.me' + 路径
      if (path.includes('v1')) {
        url = 'https://api.bento.me' + path;
      }
    
      // 如果 URL 为 "https://bento.me/",URL 将更改为 https://bento.me/' 后加上 BENTO User ID
      if (url === 'https://bento.me/') {
        url = 'https://bento.me/' + BENTO_USERNAME;
      }
    
      // 为 fetch 请求定义基本的 headers
      let headers = {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'GET,HEAD,POST,OPTIONS',
      };
    
      // 使用定义的 headers 获取 URL
      const response = await fetch(url, { headers });
    
      // 从响应 headers 中提取内容类型
      const contentType = response.headers.get('content-type');
    
      // 根据内容类型解析响应
      let results = await parseResponseByContentType(response, contentType);
    
      // 如果结果不是 ArrayBuffer
      // 将所有对 bento API 的调用替换为我们的 BASE_URL
      // 这是解决 CORS 错误的临时方案
      if (!(results instanceof ArrayBuffer)) {
        results = results.replaceAll('https://api.bento.me', BASE_URL);
      }
    
      // 将内容类型添加到 headers
      headers['content-type'] = contentType;
    
      // 返回带有结果和 headers 的新响应
      return new Response(results, { headers });
    }
  2. 通过终端进入文件夹,运行代码查看页面:

    npm run dev
  3. 部署到真实环境

    npm run deploy

5. 在 Cloudflare 配置自定义域名

  1. 先确保你需要绑定的域名 DNS 已经设置为 Cloudflare;
  2. 进入「Workers 和 Pages」找到刚才 Push 的 Worker 项目;
  3. 在「设置 - 触发器」中添加自定义域名并等待生效即可;
  4. 现在,你可以访问 lenchou.com 查看我们的 Bento 页面了。