feat(worker): redirect HTTP to HTTPS

This commit is contained in:
anonsaber 2026-10-01 02:52:01 +08:00
parent 94032a1e08
commit 1d4959a855
6 changed files with 24 additions and 7 deletions

View File

@ -35,6 +35,7 @@
+ 相同 App Password(各后端实例的 `JMAP` 可不同,`docs/deployment.md` §10.2)。 + 相同 App Password(各后端实例的 `JMAP` 可不同,`docs/deployment.md` §10.2)。
### 路由 safelist(ARCH-LB-WORKER / C-LB-SINGLE-REG-URL) ### 路由 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 的鉴权仍由后端执行。 - 透传公开 `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`。 - 只透传 `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 沦为后端任意路径的跳板)。 - 其它路径 → **404**(不透传,避免 Worker 沦为后端任意路径的跳板)。
@ -74,7 +75,7 @@
| `LB_RECONCILE_TIMEOUT_MS` | 否 | 仅 `POST /reconcile` 的单 origin 超时覆盖;默认 `320000`(须大于后端锁初租 300s + 心跳余量)。 | | `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_WORKER_TIMEOUT_MS` | 否 | 仅 `POST /worker` 的单 origin 超时覆盖;默认 `300000`(= 后端单条事件下界 `SINGLE_EVENT_CEILING_FLOOR_MS`)。一次排空 batch 条(默认 10,硬上限 10),batch 拉大时需相应上调。 |
| `LB_HEALTH_TTL_MS` | 否 | 健康探测缓存 TTL;默认 `30000`。 | | `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, > 默认写在 `wrangler.toml` 的 `[vars]`(**明文例外**,因为当前值只是公开可达的 https origin,
> 不是凭据)。一旦要放内网地址、带内嵌凭据的 URL、或不想公开的 staging 主机名, > 不是凭据)。一旦要放内网地址、带内嵌凭据的 URL、或不想公开的 staging 主机名,

View File

@ -80,7 +80,12 @@ const ROUTE_METHODS = Object.freeze({
* @returns {Promise<Response>} * @returns {Promise<Response>}
*/ */
export async function handleFetch(request, env) { 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 精神)。 // LB 级健康聚合探针(不含敏感信息,SAF-PROBE-PUBLIC 精神)。
// 挂在 /healthz-worker:/healthz 保留给源站自己的健康检查(透传),这样入站域名上 // 挂在 /healthz-worker:/healthz 保留给源站自己的健康检查(透传),这样入站域名上

View File

@ -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 () => { test("Worker GET /healthz-worker aggregates backend probes without touching forwarded routes", async () => {
const restore = stubFetch(async (url) => new Response("ok", { status: 200 })); const restore = stubFetch(async (url) => new Response("ok", { status: 200 }));
try { try {

View File

@ -51,4 +51,4 @@ compatibility_flags = ["nodejs_compat_v2"]
# LB_VERSION 是例外——它是版本标识,必须跟代码同版本、可 diff,写进 dashboard 反而容易漂。 # LB_VERSION 是例外——它是版本标识,必须跟代码同版本、可 diff,写进 dashboard 反而容易漂。
[vars] [vars]
BACKEND_ORIGINS_JSON = '["https://messageweave-eu-1.motofans.club"]' BACKEND_ORIGINS_JSON = '["https://messageweave-eu-1.motofans.club"]'
LB_VERSION = "2026.10.3" LB_VERSION = "2026.10.4"

View File

@ -198,9 +198,10 @@ business credentials and Redis state.
### 10.4 Routes and failover ### 10.4 Routes and failover
The Worker rejects unregistered routes with `404` and wrong methods with `405`. Ordinary HTTP requests to the Worker receive a permanent `308` redirect to the same HTTPS URL before
requests try at most `LB_MAX_ATTEMPTS` origins (default two), and only a timeout or `5xx` route validation or forwarding. The Worker rejects unregistered routes with `404` and wrong
triggers failover. `/reconcile` and `/worker` are single-attempt routes with longer timeout 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). overrides. Use the route matrix and tuning values in the [reference](reference.md#4-gateway-vs-backend-route-matrix).
### 10.5 Callback URLs ### 10.5 Callback URLs

View File

@ -186,7 +186,8 @@ Worker 传递请求标头和正文。仍需要后端身份验证
### 10.4 Routes and failover ### 10.4 Routes and failover
Worker 使用“404”拒绝未注册的路由,并使用“405”拒绝错误的方法。普通 HTTP 请求访问 Worker 时,会先收到永久的 `308` 重定向,前往路径和查询参数相同的
HTTPS URL,之后才进行路由校验或转发。Worker 使用“404”拒绝未注册的路由,并使用“405”拒绝错误的方法。普通
请求最多尝试“LB_MAX_ATTEMPTS”来源(默认两个),并且只有超时或“5xx” 请求最多尝试“LB_MAX_ATTEMPTS”来源(默认两个),并且只有超时或“5xx”
触发故障转移。 `/reconcile` 和 `/worker` 是具有较长超时时间的单次尝试路由 触发故障转移。 `/reconcile` 和 `/worker` 是具有较长超时时间的单次尝试路由
覆盖。使用[参考](reference.zh-CN.md#4-gateway-vs-backend-route-matrix)中的路由矩阵和调整值。 覆盖。使用[参考](reference.zh-CN.md#4-gateway-vs-backend-route-matrix)中的路由矩阵和调整值。