Logo TodTom休闲时光

Cloudflare Worker 实战:将 Trilium 笔记分享页完美映射为根域名博客并过审 AdSense

前言#

在使用 Trilium 搭建个人笔记系统时,我们通常会利用其“分享”功能将笔记发布为博客。然而,默认的分享路径通常是 notes.xxx.org/share/Index。如果你想直接使用根域名 xxx.org 作为博客入口,并且希望通过 Google AdSense 的审核(要求根域名下必须有内容且存在 ads.txt),简单的 DNS 映射或 Tunnel 直连是无法满足需求的。

本文将分享如何通过 Cloudflare Workers 巧妙地解决域名映射、样式丢失以及 AdSense 验证三大难题。

文章图片

基于 Cloudflare Worker + Tunnel 的 Trilium 博客边缘映射架构图


1. 核心需求#

  • 根域名访问:输入 xxx.org 直接看到博客首页,而不是 Trilium 登录界面。
  • AdSense 兼容:在 xxx.org/ads.txt 必须能直接读取到广告验证代码。
  • 无感中转:不改变浏览器地址栏域名,保持原有的 Cloudflare Tunnel 穿透架构。

2. 初始尝试与遇坑记录#

坑一:简单的 Redirect 或反向代理导致 404#

最初只在 Worker 中处理了 ads.txt 的请求,其余请求直接返回 404 Not Found。这导致访问根域名时直接报错,AdSense 爬虫无法抓取首页内容,审核被拒。

坑二:页面“素颜”(样式完全丢失)#

当我们尝试通过 Worker 抓取首页 HTML 时,发现页面虽然能打开,但没有任何排版和图片。 原因分析: Trilium 的资源路径(CSS/JS/图片)通常是相对路径或 /share/api/...。当域名从 notes.xxx.org 变为 xxx.org 时,浏览器会去 xxx.org/api/... 请求资源,而这些资源在根域名下并不存在。此外,如果 Host 请求头不匹配,Cloudflare Tunnel 可能会直接拒绝连接。


3. 终极解决方案:智能 Worker 脚本#

通过在 Cloudflare Worker 中编写逻辑,我们实现了一个“透明代理”。它不仅能提供 ads.txt,还能自动补全资源路径并修正 Host 头。

操作步骤:#

  1. 创建 Worker:在 Cloudflare 控制台新建一个名为 blog-handler 的 Worker。
  2. 绑定自定义域:在 Worker 的 Settings -> Triggers 中,添加你的根域名 xxx.org
  3. 配置 DNS:确保 xxx.org 的 DNS 记录类型为 Worker,且代理状态为“橙色云彩”。

完整代码实现:#

export default {
  async fetch(request) {
    const url = new URL(request.url);
    // 你的后台实际访问地址(即原本带 /share 的地址)
    const targetBase = "https://notes.xxx.org"; 

    // 1. 处理 Google AdSense 的 ads.txt (优先级最高)
    if (url.pathname === '/ads.txt') {
      return new Response('google.com, pub-xxxxxxxxxxxxxxxx, DIRECT, f08c47fec0942fa0', {
        headers: { 'content-type': 'text/plain;charset=UTF-8' },
      });
    }

    // 2. 构造目标路径映射
    let targetPath = url.pathname;

    // 场景 A:访问根目录,直接指向 Trilium 的 Index 分享页
    if (targetPath === '/' || targetPath === '') {
      targetPath = '/share/Index';
    } 
    // 场景 B:补全缺失的路径前缀(解决样式丢失的关键)
    // 如果路径不以 /share/ 开头,说明是浏览器请求的相对资源,我们需要手动补上
    else if (!targetPath.startsWith('/share/')) {
      targetPath = '/share' + targetPath;
    }

    const newUrl = targetBase + targetPath + url.search;

    // 3. 发起请求并修正 Host 头
    const modifiedRequest = new Request(newUrl, {
      method: request.method,
      headers: new Headers(request.headers),
      redirect: 'follow'
    });

    // 必须删除原始请求中的 Host,让 fetch 自动根据 targetBase 设置正确的 Host
    // 否则 Cloudflare Tunnel 会因为域名不匹配报错
    modifiedRequest.headers.delete("Host");

    // 4. (进阶) 增加静态资源缓存,提升加载速度
    let response = await fetch(modifiedRequest);
    const contentType = response.headers.get("Content-Type") || "";
    if (contentType.includes("image") || contentType.includes("css") || contentType.includes("javascript")) {
        response = new Response(response.body, response);
        response.headers.set("Cache-Control", "public, max-age=3600");
    }

    return response;
  }
};

4. 方案总结与优势#

  • 完美解决 AdSense 审核:根域名有内容,ads.txt 位置正确,爬虫满分通过。
  • 样式自动修复:通过脚本逻辑自动识别并补全 /share/ 路径,彻底解决页面乱码。
  • 性能不降反升:虽然经过了 Worker 中转,但由于加入了边缘缓存(Cache-Control),图片和 CSS 的二次加载速度远快于直接从 NAS 穿透读取。
  • 隐匿后台:用户和爬虫全程感知不到 notes.xxx.org 这个二级域名的存在,品牌统一性更强。

5. 常见问题排查(Checklist)#

  • 依然 404? 检查 Worker 是否真的绑定到了 xxx.org
  • 还是没样式? 在浏览器按 F12 查看 Network 选项卡,确认红色报错请求的 URL 是否少了 /share
  • 不生效? 记得每次修改代码后都要点击 "Save and Deploy",并清理浏览器缓存。

希望这篇指南能帮到同样在使用 Trilium 搭建博客的朋友。如果有更复杂的路径跳转需求,Worker 的灵活性几乎可以满足你所有的想象。