Download deploy/cloudflare-worker/dev-server.mjs from a3216/gcli2api: direct link, hf CLI and curl.
- Browser
- Download file 4.6 kB
-
https://huggingface.co/spaces/a3216/gcli2api/resolve/main/deploy/cloudflare-worker/dev-server.mjs
- Command line
-
hf download hf://spaces/a3216/gcli2api/deploy/cloudflare-worker/dev-server.mjs
-
curl -L -o dev-server.mjs https://huggingface.co/spaces/a3216/gcli2api/resolve/main/deploy/cloudflare-worker/dev-server.mjs
4.6 kB
| /** | |
| * worker.js 本地开发/验证服务器。 | |
| * | |
| * 为什么需要它:Worker 只有在部署到 Cloudflare 之后才会真正接管 | |
| * cli.3216gemini.dpdns.org —— 万一代理逻辑写错,你的域名当场就废了。 | |
| * 这个脚本用 Node 起一个本地 HTTP 服务,**原样执行同一个 worker.js** | |
| * (直接 import,不做任何改写),把它转发到真实的 HF Space, | |
| * 于是你可以在本地先把每一条路径验完,再决定要不要 deploy。 | |
| * | |
| * 用法: | |
| * node dev-server.mjs # 监听 127.0.0.1:8787 | |
| * PORT=9000 node dev-server.mjs | |
| * ORIGIN=https://other-space.hf.space node dev-server.mjs | |
| * | |
| * 然后另开一个终端: | |
| * curl -i http://127.0.0.1:8787/healthz # 应返回网关的 JSON | |
| * curl -i http://127.0.0.1:8787/ # 应是 302 → /panel/(不被跟随) | |
| * curl -s http://127.0.0.1:8787/__cron # 手动跑一次保活定时器(看日志) | |
| * | |
| * 注意: | |
| * - 本脚本会真实请求 HF Space。若 Space 正在休眠,第一次 /healthz 会等 | |
| * 30~60s 冷启动,这是正常现象(也正是 cron 保活要解决的问题)。 | |
| * - /__cron 是本地专用路径,永远不会被代理到源站,部署后的 Worker 里没有它。 | |
| * - 绝不把 .dev.vars 提交进版本库(见同目录 README)。 | |
| */ | |
| import http from "node:http"; | |
| import { Readable } from "node:stream"; | |
| import worker from "./worker.js"; | |
| const PORT = Number(process.env.PORT || 8787); | |
| const HOST = process.env.HOST || "127.0.0.1"; | |
| const CRON = process.env.CRON || "*/5 * * * *"; | |
| /** 把 Node 的 IncomingMessage 头转成 Web Headers。 */ | |
| function toWebHeaders(nodeHeaders) { | |
| const h = new Headers(); | |
| for (const [name, value] of Object.entries(nodeHeaders)) { | |
| if (value === undefined) continue; | |
| if (Array.isArray(value)) { | |
| for (const v of value) h.append(name, v); | |
| } else { | |
| h.set(name, value); | |
| } | |
| } | |
| return h; | |
| } | |
| const server = http.createServer(async (req, res) => { | |
| try { | |
| exphost: { | |
| // 本地专用:手动触发一次 scheduled(),用来验证保活/重试/日志逻辑。 | |
| if (req.url === "/__cron") { | |
| console.log(`[dev] 手动触发 scheduled() cron="${CRON}"`); | |
| await worker.scheduled({ cron: CRON }, process.env, {}); | |
| res.writeHead(200, { "content-type": "application/json; charset=utf-8" }); | |
| res.end(JSON.stringify({ ok: true, triggered: CRON }, null, 2) + "\n"); | |
| break exphost; | |
| } | |
| // 本地专用:探活,不会打到源站。 | |
| if (req.url === "/__ping") { | |
| res.writeHead(200, { "content-type": "text/plain" }); | |
| res.end("dev-server alive\n"); | |
| break exphost; | |
| } | |
| const url = new URL(req.url, `http://${HOST}:${PORT}`); | |
| const hasBody = req.method !== "GET" && req.method !== "HEAD"; | |
| // Node 要求流式请求体显式声明 duplex:"half";Cloudflare Workers 不需要, | |
| // 所以这个参数只在这里出现,worker.js 本身保持平台无关。 | |
| const request = new Request(url, { | |
| method: req.method, | |
| headers: toWebHeaders(req.headers), | |
| body: hasBody ? req : undefined, | |
| duplex: hasBody ? "half" : undefined, | |
| redirect: "manual", | |
| }); | |
| const response = await worker.fetch(request, process.env, {}); | |
| const outHeaders = {}; | |
| for (const [k, v] of response.headers) outHeaders[k] = v; | |
| res.writeHead(response.status, outHeaders); | |
| if (response.body) { | |
| // 关键:流式回传,不缓冲 —— SSE 必须这样,否则流式体验当场报废。 | |
| await new Promise((resolve, reject) => { | |
| Readable.fromWeb(response.body).pipe(res).on("finish", resolve).on("error", reject); | |
| }); | |
| } else { | |
| res.end(); | |
| } | |
| } | |
| } catch (err) { | |
| console.error("[dev] 处理请求失败:", err); | |
| if (!res.headersSent) { | |
| res.writeHead(502, { "content-type": "application/json; charset=utf-8" }); | |
| } | |
| res.end(JSON.stringify({ error: "dev_server_error", detail: String(err && err.message) }) + "\n"); | |
| } | |
| }); | |
| server.listen(PORT, HOST, () => { | |
| console.log(`[dev] worker.js 本地验证服务: http://${HOST}:${PORT}`); | |
| console.log(`[dev] 源站 ORIGIN = ${process.env.ORIGIN || "(默认 https://a3216-gcli2api.hf.space)"}`); | |
| console.log("[dev] 试试:"); | |
| console.log(`[dev] curl -i http://${HOST}:${PORT}/healthz`); | |
| console.log(`[dev] curl -i http://${HOST}:${PORT}/`); | |
| console.log(`[dev] curl -s http://${HOST}:${PORT}/__cron`); | |
| }); | |