From 1d4959a85543dccf401f6af0fb330c06bab8c92a Mon Sep 17 00:00:00 2001 From: anonsaber Date: Thu, 1 Oct 2026 02:52:01 +0800 Subject: [PATCH] feat(worker): redirect HTTP to HTTPS --- cloudflare-worker/README.md | 3 ++- cloudflare-worker/src/index.js | 7 ++++++- cloudflare-worker/test/index.test.js | 9 +++++++++ cloudflare-worker/wrangler.toml | 2 +- docs/deployment.md | 7 ++++--- docs/deployment.zh-CN.md | 3 ++- 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/cloudflare-worker/README.md b/cloudflare-worker/README.md index a45038f..2ced1fd 100644 --- a/cloudflare-worker/README.md +++ b/cloudflare-worker/README.md @@ -35,6 +35,7 @@ + 相同 App Password(各后端实例的 `JMAP` 可不同,`docs/deployment.md` §10.2)。 ### 路由 safelist(ARCH-LB-WORKER / C-LB-SINGLE-REG-URL) +- HTTP requests receive a permanent `308` redirect to the same HTTPS URL before route validation or forwarding. - 透传公开 `GET /api/status` 启动状态,以及管理 SPA API:`POST /api/admin/session[/revoke]`、`GET|PUT /api/enabled`(业务总开关,SPA 服务卡片读写)、`GET|PUT /api/config`、`GET|PUT /api/business-config`(读回 + 增量保存)、`POST /api/business-config/preflight`(保存前逐组件连通性预检)。启动状态只包含缺少的环境变量名称;管理 API 的鉴权仍由后端执行。 - 只透传 `POST /webhook/tg`、`POST /push/jmap`、`POST /api/push/register`、`POST /api/telegram/register-webhook`、`POST /api/push/disable`、`POST /reconcile`、`POST /worker`、`GET /ready`。 - 其它路径 → **404**(不透传,避免 Worker 沦为后端任意路径的跳板)。 @@ -74,7 +75,7 @@ | `LB_RECONCILE_TIMEOUT_MS` | 否 | 仅 `POST /reconcile` 的单 origin 超时覆盖;默认 `320000`(须大于后端锁初租 300s + 心跳余量)。 | | `LB_WORKER_TIMEOUT_MS` | 否 | 仅 `POST /worker` 的单 origin 超时覆盖;默认 `300000`(= 后端单条事件下界 `SINGLE_EVENT_CEILING_FLOOR_MS`)。一次排空 batch 条(默认 10,硬上限 10),batch 拉大时需相应上调。 | | `LB_HEALTH_TTL_MS` | 否 | 健康探测缓存 TTL;默认 `30000`。 | -| `LB_VERSION` | 否 | `/healthz-worker` 响应体里的 `version` 字段,用于确认线上是哪次部署在回答;取自 `wrangler.toml` 的 `[vars]`(当前 `2026.10.3`),改 LB 逻辑的提交同时 bump | +| `LB_VERSION` | 否 | `/healthz-worker` 响应体里的 `version` 字段,用于确认线上是哪次部署在回答;取自 `wrangler.toml` 的 `[vars]`(当前 `2026.10.4`),改 LB 逻辑的提交同时 bump | > 默认写在 `wrangler.toml` 的 `[vars]`(**明文例外**,因为当前值只是公开可达的 https origin, > 不是凭据)。一旦要放内网地址、带内嵌凭据的 URL、或不想公开的 staging 主机名, diff --git a/cloudflare-worker/src/index.js b/cloudflare-worker/src/index.js index ff55c4f..70946ab 100644 --- a/cloudflare-worker/src/index.js +++ b/cloudflare-worker/src/index.js @@ -80,7 +80,12 @@ const ROUTE_METHODS = Object.freeze({ * @returns {Promise} */ export async function handleFetch(request, env) { - const path = new URL(request.url).pathname; + const requestUrl = new URL(request.url); + if (requestUrl.protocol === "http:") { + requestUrl.protocol = "https:"; + return Response.redirect(requestUrl.toString(), 308); + } + const path = requestUrl.pathname; // LB 级健康聚合探针(不含敏感信息,SAF-PROBE-PUBLIC 精神)。 // 挂在 /healthz-worker:/healthz 保留给源站自己的健康检查(透传),这样入站域名上 diff --git a/cloudflare-worker/test/index.test.js b/cloudflare-worker/test/index.test.js index c47cbda..4fde326 100644 --- a/cloudflare-worker/test/index.test.js +++ b/cloudflare-worker/test/index.test.js @@ -25,6 +25,15 @@ function stubFetch(impl) { }; } +test("Worker redirects HTTP requests to the same HTTPS URL before forwarding", async () => { + const res = await handleFetch( + new Request("http://lb.example/api/status?from=http#fragment"), + makeEnv(), + ); + assert.equal(res.status, 308); + assert.equal(res.headers.get("location"), "https://lb.example/api/status?from=http#fragment"); +}); + test("Worker GET /healthz-worker aggregates backend probes without touching forwarded routes", async () => { const restore = stubFetch(async (url) => new Response("ok", { status: 200 })); try { diff --git a/cloudflare-worker/wrangler.toml b/cloudflare-worker/wrangler.toml index b4c4366..34c4456 100644 --- a/cloudflare-worker/wrangler.toml +++ b/cloudflare-worker/wrangler.toml @@ -51,4 +51,4 @@ compatibility_flags = ["nodejs_compat_v2"] # LB_VERSION 是例外——它是版本标识,必须跟代码同版本、可 diff,写进 dashboard 反而容易漂。 [vars] BACKEND_ORIGINS_JSON = '["https://messageweave-eu-1.motofans.club"]' -LB_VERSION = "2026.10.3" +LB_VERSION = "2026.10.4" diff --git a/docs/deployment.md b/docs/deployment.md index da9abb8..dba45e2 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -198,9 +198,10 @@ business credentials and Redis state. ### 10.4 Routes and failover -The Worker rejects unregistered routes with `404` and wrong methods with `405`. Ordinary -requests try at most `LB_MAX_ATTEMPTS` origins (default two), and only a timeout or `5xx` -triggers failover. `/reconcile` and `/worker` are single-attempt routes with longer timeout +HTTP requests to the Worker receive a permanent `308` redirect to the same HTTPS URL before +route validation or forwarding. The Worker rejects unregistered routes with `404` and wrong +methods with `405`. Ordinary requests try at most `LB_MAX_ATTEMPTS` origins (default two), and +only a timeout or `5xx` triggers failover. `/reconcile` and `/worker` are single-attempt routes with longer timeout overrides. Use the route matrix and tuning values in the [reference](reference.md#4-gateway-vs-backend-route-matrix). ### 10.5 Callback URLs diff --git a/docs/deployment.zh-CN.md b/docs/deployment.zh-CN.md index 8c4978d..b1fdd67 100644 --- a/docs/deployment.zh-CN.md +++ b/docs/deployment.zh-CN.md @@ -186,7 +186,8 @@ Worker 传递请求标头和正文。仍需要后端身份验证 ### 10.4 Routes and failover -Worker 使用“404”拒绝未注册的路由,并使用“405”拒绝错误的方法。普通 +HTTP 请求访问 Worker 时,会先收到永久的 `308` 重定向,前往路径和查询参数相同的 +HTTPS URL,之后才进行路由校验或转发。Worker 使用“404”拒绝未注册的路由,并使用“405”拒绝错误的方法。普通 请求最多尝试“LB_MAX_ATTEMPTS”来源(默认两个),并且只有超时或“5xx” 触发故障转移。 `/reconcile` 和 `/worker` 是具有较长超时时间的单次尝试路由 覆盖。使用[参考](reference.zh-CN.md#4-gateway-vs-backend-route-matrix)中的路由矩阵和调整值。