将 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 新增「路由约定」说明。
53 lines
1.7 KiB
Python
53 lines
1.7 KiB
Python
"""验证删除白板时,在线 WS 连接被服务端踢出(收到 error 帧并断连)。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import asyncio
|
||
import json
|
||
import urllib.request
|
||
|
||
import websockets
|
||
|
||
BASE_WS = "ws://127.0.0.1:6867/api/ws/wb"
|
||
BOARD = "kicktest"
|
||
AUTH = "Basic YTo2NjUxMTMxNQ==" # a:66511315
|
||
|
||
|
||
async def main() -> None:
|
||
async with websockets.connect(f"{BASE_WS}/{BOARD}") as a:
|
||
await a.send(json.dumps({"type": "hello", "client_id": "A"}))
|
||
init = json.loads(await asyncio.wait_for(a.recv(), timeout=2))
|
||
assert init["type"] == "init"
|
||
print("A connected, init received")
|
||
|
||
# 通过 REST 删除白板(带 Basic Auth)
|
||
req = urllib.request.Request(
|
||
f"http://127.0.0.1:6867/api/admin/wb/{BOARD}",
|
||
method="DELETE",
|
||
headers={"Authorization": AUTH},
|
||
)
|
||
with urllib.request.urlopen(req) as r:
|
||
print("delete response:", r.read().decode())
|
||
|
||
# A 应收到 error 帧随后连接关闭
|
||
try:
|
||
raw = await asyncio.wait_for(a.recv(), timeout=3)
|
||
msg = json.loads(raw)
|
||
print("A received:", msg)
|
||
assert msg["type"] == "error", "应收到 error 通知"
|
||
except (websockets.ConnectionClosed, asyncio.TimeoutError) as e:
|
||
print("连接关闭/超时:", e)
|
||
|
||
# 确认连接已断
|
||
try:
|
||
await asyncio.wait_for(a.recv(), timeout=2)
|
||
print("ERROR: 连接仍存活(应已断开)")
|
||
except websockets.ConnectionClosed:
|
||
print("连接已被服务端关闭 ✅")
|
||
except asyncio.TimeoutError:
|
||
print("连接未关闭但无消息(部分通过)")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
asyncio.run(main())
|