feat: 所有入口统一到 /api/ 前缀

将 zTools2 托管的页面/静态/探针/WebSocket 路由全部从顶级路径迁移到 /api/ 下:
- 页面:/pdf -> /api/pdf、/pdf-admin -> /api/pdf-admin、/upload -> /api/upload、
  /files -> /api/files-page、/wb/{id} -> /api/wb-page/{id}、/wb-admin -> /api/wb-admin
  (页面类加 -page 后缀以规避同名 REST API /api/files、/api/wb/{id})
- 静态资源:/static -> /api/static
- 探针:/health -> /api/health
- WebSocket:/ws/wb/{id} -> /api/ws/wb/{id}
- 前端 HTML 壳与 JS 中的资源/页间链接/WS URL 同步更新
- 手动测试脚本 BASE_WS 同步

这样反代与 vite proxy 只需一条 /api/ 规则即可转发全部入口;
前端 iframe 用同源相对路径 /api/pdf,与环境无关,不再误打到其它环境域名。
README 新增「路由约定」说明。
This commit is contained in:
2026-07-27 15:42:47 +08:00
parent 729c77e98b
commit ff2ad3fcb3
13 changed files with 75 additions and 60 deletions

View File

@@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>文件浏览 - zikai</title>
<link rel="stylesheet" href="/static/common.css">
<link rel="stylesheet" href="/static/file_browser.css">
<link rel="stylesheet" href="/api/static/common.css">
<link rel="stylesheet" href="/api/static/file_browser.css">
</head>
<body>
<div class="wrap">
@@ -39,9 +39,9 @@
<div id="pager" class="pager hidden"></div>
<p class="foot"><a class="link" href="/upload">上传文件</a> · zikai file service</p>
<p class="foot"><a class="link" href="/api/upload">上传文件</a> · zikai file service</p>
</div>
<script src="/static/common.js"></script>
<script src="/static/file_browser.js"></script>
<script src="/api/static/common.js"></script>
<script src="/api/static/file_browser.js"></script>
</body>
</html>

View File

@@ -73,7 +73,7 @@
function render() {
if (!state.items.length) {
listEl.innerHTML = '<div class="empty">还没有文件。去 <a class="link" href="/upload">上传</a> 一个吧。</div>';
listEl.innerHTML = '<div class="empty">还没有文件。去 <a class="link" href="/api/upload">上传</a> 一个吧。</div>';
renderSelection();
return;
}

View File

@@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>PDF 转换 - zikai</title>
<link rel="stylesheet" href="/static/common.css">
<link rel="stylesheet" href="/static/pdf.css">
<link rel="stylesheet" href="/api/static/common.css">
<link rel="stylesheet" href="/api/static/pdf.css">
</head>
<body>
<div class="wrap">
@@ -38,7 +38,7 @@
<p class="foot">zikai file service</p>
</div>
<script src="/static/common.js"></script>
<script src="/static/pdf.js"></script>
<script src="/api/static/common.js"></script>
<script src="/api/static/pdf.js"></script>
</body>
</html>

View File

@@ -4,9 +4,9 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>PDF 转换管理 - zikai</title>
<link rel="stylesheet" href="/static/common.css">
<link rel="stylesheet" href="/static/pdf.css">
<link rel="stylesheet" href="/static/pdf_admin.css">
<link rel="stylesheet" href="/api/static/common.css">
<link rel="stylesheet" href="/api/static/pdf.css">
<link rel="stylesheet" href="/api/static/pdf_admin.css">
</head>
<body>
<div class="wrap">
@@ -22,9 +22,9 @@
<div class="skel">加载中…</div>
</div>
<p class="foot"><a class="link" href="/pdf">PDF 转换页</a> · zikai file service</p>
<p class="foot"><a class="link" href="/api/pdf">PDF 转换页</a> · zikai file service</p>
</div>
<script src="/static/common.js"></script>
<script src="/static/pdf_admin.js"></script>
<script src="/api/static/common.js"></script>
<script src="/api/static/pdf_admin.js"></script>
</body>
</html>

View File

@@ -8,8 +8,8 @@
禁用 common.css 的 prefers-color-scheme: dark保持背景与嵌入站一致 -->
<meta name="color-scheme" content="light">
<title>记事本 - zikai</title>
<link rel="stylesheet" href="/static/common.css">
<link rel="stylesheet" href="/static/whiteboard.css">
<link rel="stylesheet" href="/api/static/common.css">
<link rel="stylesheet" href="/api/static/whiteboard.css">
</head>
<body>
<div class="wb-app">
@@ -30,7 +30,7 @@
<div class="wb-status" id="status">连接中…</div>
</main>
</div>
<script src="/static/common.js"></script>
<script src="/static/whiteboard.js"></script>
<script src="/api/static/common.js"></script>
<script src="/api/static/whiteboard.js"></script>
</body>
</html>

View File

@@ -8,7 +8,7 @@
const { toast, copyText } = window.ZK;
// ---------- 从 URL 解析 board_id ----------
const m = location.pathname.match(/^\/wb\/([^/]+)\/?$/);
const m = location.pathname.match(/^\/api\/wb-page\/([^/]+)\/?$/);
let boardId = m ? decodeURIComponent(m[1]) : "default";
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(boardId)) boardId = "default";
document.getElementById("boardId").textContent = boardId;
@@ -81,7 +81,7 @@
});
copyLinkBtn.addEventListener("click", async () => {
const url = `${location.origin}/wb/${boardId}`;
const url = `${location.origin}/api/wb-page/${boardId}`;
const ok = await copyText(url);
toast(ok ? "链接已复制" : "复制失败");
});
@@ -143,7 +143,7 @@
// ---------- WebSocket ----------
function wsUrl() {
const proto = location.protocol === "https:" ? "wss:" : "ws:";
return `${proto}//${location.host}/ws/wb/${encodeURIComponent(boardId)}`;
return `${proto}//${location.host}/api/ws/wb/${encodeURIComponent(boardId)}`;
}
function connect() {

View File

@@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>白板管理 - zikai</title>
<link rel="stylesheet" href="/static/common.css">
<link rel="stylesheet" href="/static/whiteboard_admin.css">
<link rel="stylesheet" href="/api/static/common.css">
<link rel="stylesheet" href="/api/static/whiteboard_admin.css">
</head>
<body>
<div class="wrap">
@@ -22,9 +22,9 @@
<div class="skel">加载中…</div>
</div>
<p class="foot"><a class="link" href="/upload">上传文件</a> · <a class="link" href="/files">文件浏览</a> · zikai</p>
<p class="foot"><a class="link" href="/api/upload">上传文件</a> · <a class="link" href="/api/files-page">文件浏览</a> · zikai</p>
</div>
<script src="/static/common.js"></script>
<script src="/static/whiteboard_admin.js"></script>
<script src="/api/static/common.js"></script>
<script src="/api/static/whiteboard_admin.js"></script>
</body>
</html>

View File

@@ -11,7 +11,7 @@
newBtn.addEventListener("click", () => {
// 生成一个随机 board_id 并打开(访问即创建)
const id = "b_" + Math.random().toString(36).slice(2, 10);
window.open(`/wb/${id}`, "_blank");
window.open(`/api/wb-page/${id}`, "_blank");
});
async function load() {
@@ -47,7 +47,7 @@
for (const b of items) {
const row = el("tr", null,
el("td", { class: "col-id" },
el("a", { class: "bid link", href: `/wb/${b.board_id}`, target: "_blank" }, b.board_id)
el("a", { class: "bid link", href: `/api/wb-page/${b.board_id}`, target: "_blank" }, b.board_id)
),
el("td", { class: "col-mods mono" }, String(b.edit_count ?? 0)),
el("td", { class: "col-created muted" }, fmtTime(b.created_at)),