使用静态资源提供帮助中心

CloudflareBeginner
立即练习

简介

帮助中心需要快速的公开页面、JSON 健康检查端点,以及仅限员工访问的文档。如果静态文件意外优先于处理请求的代码,就可能产生安全问题。你将先在本地观察这种行为,再配置 Worker 优先路由,并部署一套明确的策略:既保持公开网站可用,又保护模拟员工页面。

这个独立实验从 /home/labex/project/help-center 开始,环境中包含 Node.js 22.22.0、项目本地 Wrangler 4.131.1,以及预先提供的 HTML、CSS 和 JavaScript 测试文件。请使用你自己的 Cloudflare 学习账号,并运用之前学过的授权、部署和密钥文件操作技能。不需要之前创建的虚拟机、云资源、已购买的域名、数据库或付费升级。请求会计入账号的正常使用量。

所有内容和凭据均为模拟数据。保持一个终端打开。存在安全问题的基线配置只在本地使用;只有修复后的 Worker 会被部署。结束虚拟机前,请删除部署、移除本地测试凭据并退出登录。

在本地观察资源优先路由

在本步骤中,你将检查预先提供的帮助中心页面框架,并观察默认情况下匹配的文件如何优先于 Worker。测试文件中包含一个故意与 Worker 冲突的 /api/health 文件,以及一个虚假的员工手册。所有内容都是模拟数据,第一种配置只在本地使用。

cd /home/labex/project/help-center
node --version
npx wrangler --version
ls -R public

预期结果是 Node v22.22.0 和 Wrangler 4.131.1。安装程序已经安装了项目本地工具;如果要在其他位置重现此环境,请结合项目锁定文件使用 npm cipublic 目录包含 HTML、CSS、浏览器 JavaScript,以及两个用于测试路由的文件。不要把凭据或真实内部文档放入该目录。

WORKER_NAME="labex-help-$(openssl rand -hex 6)"
cat > wrangler.jsonc <<CONFIG
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-09-14",
  "workers_dev": true,
  "preview_urls": false,
  "assets": {
    "directory": "./public",
    "binding": "ASSETS",
    "html_handling": "none",
    "not_found_handling": "none",
    "run_worker_first": false
  }
}
CONFIG

directory 指定要上传的文件,binding 则让处理程序可以通过 env.ASSETS 访问这些文件。html_handling: none 保留显式文件路径;not_found_handling: none 避免自动回退到单页应用页面。由于已禁用自动 HTML 处理,处理程序会将 / 显式映射到 /index.html。处理程序计划为健康检查请求返回 JSON,并将其他路径交给资源存储处理。

cat > src/index.js <<'JS'
export default {
  async fetch(request, env) {
    if (new URL(request.url).pathname === '/api/health') {
      return Response.json({status: 'ok', service: 'help-center'});
    }
    const assetUrl = new URL(request.url);
    if (assetUrl.pathname === '/') assetUrl.pathname = '/index.html';
    return env.ASSETS.fetch(new Request(assetUrl, request));
  }
};
JS
npx wrangler dev --ip 0.0.0.0 --port 8080 > dev.log 2>&1 &
cat dev.log

等待日志报告服务已就绪后再继续;如果需要,可以重复执行 cat

curl -i http://127.0.0.1:8080/
curl -i http://127.0.0.1:8080/styles.css
curl -i http://127.0.0.1:8080/api/health
curl -i http://127.0.0.1:8080/staff/handbook.html

首页和 CSS 应返回 200。健康检查请求返回的是静态文本 STATIC_HEALTH_PLACEHOLDER,而不是处理程序生成的 JSON,因为匹配到的资源优先级更高。模拟员工手册也可以被直接读取。这说明了路由优先级,并不代表部署是安全的。不要部署这套基线配置。修改配置前,先完成验证。

如果实验环境提供 Web 8080 预览,现在打开它。帮助中心页面框架会加载,但状态栏显示 API 状态不可用,因为浏览器预期收到 JSON。请以命令行响应作为路由检查的依据;预览页面仅用于检查视觉效果。

下面的示例展示了开始时的问题:页面和样式表可以加载,但 API status unavailable 表示浏览器没有收到预期的健康检查 JSON。仅页面框架能够显示,并不能证明 API 路由正常工作。

路由修复前的帮助中心,显示 API status unavailable

让 Worker 先于资源运行并保护员工内容

在本步骤中,你将让处理程序先于任何静态资源匹配执行。先查看 jobs 显示的实际开发进程;下面的示例假定进程编号为 1。

jobs
kill %1
cat > wrangler.jsonc <<CONFIG
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-09-14",
  "workers_dev": true,
  "preview_urls": false,
  "assets": {
    "directory": "./public",
    "binding": "ASSETS",
    "html_handling": "none",
    "not_found_handling": "none",
    "run_worker_first": true
  }
}
CONFIG

设置 run_worker_first: true 后,每个请求都会进入处理程序,包括原本可以直接匹配到文件的请求。你也可以使用选择性的路由模式,但这个小型应用采用单一的显式路由策略。请参阅静态资源配置

按照之前学过的密钥文件流程,生成一次性员工凭据。umask 会限制新建文件的权限。这是仅供实验使用的持有者令牌,不是账号 API 令牌。不要将它放入公开文件、浏览器 JavaScript、URL 或日志中。

umask 077
STAFF_TOKEN=$(openssl rand -hex 24)
printf 'STAFF_TOKEN=%s\n' "$STAFF_TOKEN" > .dev.vars
cat .gitignore

确认 .dev.vars*.env* 已被忽略。使用下面的完整策略替换处理程序。它会对路径进行一次解码,以 JSON 形式提供健康检查,只允许列出的公开文件,在获取员工资源前检查员工凭据,并拒绝未知路径。发送给 ASSETS 的请求不包含客户端的 Authorization 标头。受保护的响应使用 private, no-store

cat > src/index.js <<'JS'
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    let path;
    try { path = decodeURIComponent(url.pathname); }
    catch { return Response.json({error: 'not_found'}, {status: 404}); }
    if (path === '/api/health') {
      if (request.method !== 'GET') {
        return Response.json({error: 'method_not_allowed'}, {status: 405, headers: {Allow: 'GET'}});
      }
      return Response.json({status: 'ok', service: 'help-center'});
    }
    const publicPaths = ['/', '/index.html', '/styles.css', '/app.js'];
    if (path === '/staff/handbook.html') {
      if (!env.STAFF_TOKEN) return Response.json({error: 'staff_unconfigured'}, {status: 503});
      if (request.headers.get('Authorization') !== `Bearer ${env.STAFF_TOKEN}`) {
        return Response.json({error: 'unauthorized'}, {status: 401});
      }
    } else if (!publicPaths.includes(path)) {
      return Response.json({error: 'not_found'}, {status: 404});
    }
    if (!['GET', 'HEAD'].includes(request.method)) {
      return Response.json({error: 'method_not_allowed'}, {status: 405, headers: {Allow: 'GET, HEAD'}});
    }
    url.pathname = path === '/' ? '/index.html' : path;
    // Only known paths reach the asset store, after any required authorization.
    const response = await env.ASSETS.fetch(new Request(url, {method: request.method}));
    if (path === '/staff/handbook.html') {
      const headers = new Headers(response.headers);
      headers.set('Cache-Control', 'private, no-store');
      return new Response(response.body, {status: response.status, headers});
    }
    return response;
  }
};
JS
npx wrangler dev --ip 0.0.0.0 --port 8080 > dev.log 2>&1 &
cat dev.log

服务就绪后,比较公开资源、受保护资源和未知路径的响应:

curl -i http://127.0.0.1:8080/api/health
curl -i http://127.0.0.1:8080/staff/handbook.html
curl -i http://127.0.0.1:8080/staff/handbook.html -H "Authorization: Bearer wrong-token"
curl -i http://127.0.0.1:8080/staff/handbook.html -H "Authorization: Bearer $STAFF_TOKEN"
curl -i --path-as-is http://127.0.0.1:8080/%73taff/handbook.html
curl -i http://127.0.0.1:8080/missing-page -H "Sec-Fetch-Mode: navigate"

现在,即使冲突文件仍然存在,健康检查也会返回 200 和 {"status":"ok","service":"help-center"}。缺少凭据和凭据错误时会返回 401 JSON;提供匹配的令牌时会返回模拟员工手册 HTML。经过编码的员工路径也会返回 401,未知导航路径会返回 404 JSON。删除测试文件会掩盖路由问题,因此请保留它。

刷新可选的 Web 8080 预览:状态现在应显示 API status: ok。没有凭据时,员工手册端点会返回 401 JSON。某些嵌入式浏览器会阻止导航到此响应,并继续显示之前的页面;请使用上面的 curl 结果检查响应。浏览器显示之前的页面并不表示访问成功。要授权访问,请使用带有模拟请求标头的 curl;不要将密钥粘贴到地址栏中。验证时应保持服务器运行。验证还会检查 HEAD 请求、编码路径、其他路径写法和公开资源类型。

将状态栏与之前的预览进行比较。现在显示 API status: ok,说明页面可以读取健康检查响应。这个视觉检查覆盖了公开健康检查路由;请使用上面的 curl 响应评估受保护的员工手册。

路由修复后的帮助中心,显示 API status ok

部署资源和受保护的处理程序

在本步骤中,你将只把修复后的配置部署到学习账号。先使用 jobs 查看当前本地进程的实际编号,然后停止该进程。

jobs
kill %1
npx wrangler login --device --browser=false --scopes account:read user:read workers_scripts:write workers_tail:read

在已登录的浏览器中完成显示的设备链接和代码,检查现有的 Wrangler 权限与 Background Access,然后选择你的学习账号。等待终端显示操作完成。

npx wrangler whoami --json

确认实际的账号名称和 ID,然后将下面的 YOUR_ACCOUNT_ID 替换为该 ID。保留原来的资源名称和已修复的资源设置。

cat > wrangler.jsonc <<CONFIG
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-09-14",
  "account_id": "YOUR_ACCOUNT_ID",
  "workers_dev": true,
  "preview_urls": false,
  "assets": {
    "directory": "./public",
    "binding": "ASSETS",
    "html_handling": "none",
    "not_found_handling": "none",
    "run_worker_first": true
  }
}
CONFIG
npx wrangler deploy

Wrangler 会上传 public 目录并部署处理程序。复制下面显示的完整 workers.dev URL。复用学习账号已有的子域名;首次使用的用户可以按照 Wrangler 提供的子域名提示操作。

APP_URL="https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev"
curl -i "$APP_URL/staff/handbook.html"

上传密钥前,该路由会返回 503 staff_unconfigured:处理程序会先执行,并在配置缺失时安全拒绝请求。.dev.vars 是本地配置文件,部署时不会上传。如果主机名传播延迟导致暂时没有响应,请先短暂等待并重试,再调查持续存在的错误。

npx wrangler secret bulk .dev.vars
npx wrangler secret list

确认列表中显示 STAFF_TOKEN,且不会显示其值。密钥部署可能需要一点时间才能到达所有服务位置。如果后续请求仍返回 staff_unconfigured,等待 10 秒后重复这些请求,最长等待两分钟。在执行验证前,必须确认没有凭据时稳定返回 401、携带凭据时稳定返回 200。持续不匹配时需要调查;不要将 503 作为最终结果,也不要为了让检查通过而修改授权策略。

curl -i "$APP_URL/"
curl -i "$APP_URL/api/health"
curl -i "$APP_URL/staff/handbook.html"
curl -i "$APP_URL/staff/handbook.html" -H "Authorization: Bearer $STAFF_TOKEN"
curl -i "$APP_URL/missing-page" -H "Sec-Fetch-Mode: navigate"

预期结果是:公开 HTML、健康检查 JSON、无凭据时返回 401、带凭据时返回员工手册 HTML,以及未知页面返回 404。在同一个 Dashboard 账号中,打开 Compute → Workers & Pages,找到准确的 Worker,并确认其公开 URL。使用验证检查实际的资源归属、已部署的绑定、资源内容和授权行为。你也可以在自己的浏览器中打开公开首页;不要通过 URL 发送员工令牌。这个模拟令牌门禁用于讲解路由,并不是完整的员工身份系统。

在 Worker 的 Overview 标签页中,将面包屑中的名称和关联的 workers.dev 地址与部署输出进行比较。截图中的名称和子域名只是示例;你生成的名称和账号子域名会不同。这是已部署的公开地址,而 Web 8080 预览的是本地开发服务器。打开这个已有的 Worker 不需要创建其他应用。

Overview 中已部署的帮助中心 Worker 及其公开地址

删除帮助中心部署

在本步骤中,你将删除实验 Worker,以及与其关联的资源和密钥绑定。此时仍应保持授权状态。先确认唯一名称和账号:

cat wrangler.jsonc
npx wrangler delete

检查提示中的实验名称是否准确,然后按一次 y 键。删除后,Wrangler 4.131.1 可能会报告文档中记录的旧版 Workers Sites KV 身份验证错误。不要因此扩大权限,也不要将该消息作为删除成功的证据。刷新 Workers & Pages,并使用验证功能:成功的授权资源清单中不应再出现该名称。保留无关资源、账号及其 workers.dev 子域名。

删除本地凭据并断开连接

在本步骤中,确认云端清理完成后,删除本地模拟凭据,然后断开此虚拟机。

rm .dev.vars
unset STAFF_TOKEN
npx wrangler logout
npx wrangler whoami --json

预期结果中应明确包含 "loggedIn": false;如果结构化结果存在,未认证状态导致命令以非零状态退出是正常现象。使用验证功能,然后结束虚拟机。浏览器登录状态可以继续保留;结束虚拟机或退出登录都不会替你删除云端资源。

总结

你先观察了资源优先路由,然后使用 Worker 优先处理,让 API 响应和授权检查优先于匹配到的文件。预先提供的帮助中心页面框架仍然提供公开的 HTML、CSS 和浏览器 JavaScript,同时通过显式路径处理阻止未经授权的员工请求和未知路由。你测试了编码路径和浏览器式导航,使用单独的密钥上传部署了修复后的网站,最后验证了删除和退出登录。

当静态文件与应用策略共用一个主机名时,请有意识地选择路由顺序。仅凭本地响应,无法证明已部署配置或账号身份正确。