mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 13:40:45 +00:00
修管理页 Content-Type(浏览器显示成一屏源码)
用户截图:打开 relay.xxmxxs.top/zhongzhuanzhan 看到的**不是页面, 而是整页 HTML 源码**。 根因:_send() 的 content_type 参数默认是 application/json, 我重做管理页时调它没传 text/html —— 浏览器按 JSON/纯文本处理, 就把 HTML 原样显示了。 ⚠ 更该反省的是:**我当时没发现。** 验证脚本只看了 HTTP 200 和字节数,两个都对,就以为没问题。 200 不等于页面能看 —— 响应头也得看。 顺手修的第二个问题: HEAD 请求一律返回 501 Unsupported method(没实现 do_HEAD)。 浏览器用 GET 所以页面照开,但 Cloudflare 健康检查、 很多监控/代理探测都用 HEAD,curl -I 也是。 补了 do_HEAD:按路径算出类型和长度,只回头不回体。 新增测试 _build/test_response_headers.py(9 项): * HEAD 各路径不能是 501 * 官网/管理页 Content-Type 必须是 text/html,不能是 json * favicon、产品截图必须是 image/* 并加进全量套件(阶段 3b6)。 验证:该测试 9/9 通过;全量套件 33 个阶段全部通过。
This commit is contained in:
+53
-1
@@ -1026,6 +1026,52 @@ class Handler(BaseHTTPRequestHandler):
|
||||
|
||||
# ---------------- 路由 ----------------
|
||||
|
||||
def do_HEAD(self): # noqa: N802
|
||||
"""HEAD 请求只回头,不回体。
|
||||
|
||||
之前没实现,HEAD 一律 501 Unsupported method。
|
||||
浏览器用 GET 所以页面照开,但:
|
||||
* Cloudflare 的健康检查、很多监控/代理探测会用 HEAD
|
||||
* curl -I 也是 HEAD,排查时看不到响应头很别扭
|
||||
这里按 GET 算好状态和长度,把体丢掉就行。
|
||||
"""
|
||||
RELAY.total_requests += 1
|
||||
path = self.path.split("?")[0]
|
||||
try:
|
||||
body, ctype = self._head_info(path)
|
||||
except Exception: # noqa: BLE001
|
||||
body, ctype = b"", "text/plain; charset=utf-8"
|
||||
self.send_response(200 if body is not None else 404)
|
||||
self.send_header("Content-Type", ctype)
|
||||
self.send_header("Content-Length", str(len(body or b"")))
|
||||
self.send_header("Cache-Control", "no-store")
|
||||
self.end_headers()
|
||||
|
||||
def _head_info(self, path: str) -> tuple:
|
||||
"""给 HEAD 用:算这个路径的响应类型和长度(不真的发体)。"""
|
||||
if path == "/":
|
||||
return _site_page().encode("utf-8"), "text/html; charset=utf-8"
|
||||
if path == "/v1/health":
|
||||
return b"{}", "application/json"
|
||||
if path in ("/url", "/v1/url"):
|
||||
return (public_url() or "").encode("utf-8"), \
|
||||
"text/plain; charset=utf-8"
|
||||
if path == "/favicon.ico":
|
||||
icon = Path(__file__).resolve().parent / "favicon.ico"
|
||||
return (icon.read_bytes() if icon.is_file() else b""), \
|
||||
"image/x-icon"
|
||||
if path == ADMIN_PATH:
|
||||
return b"", "text/html; charset=utf-8"
|
||||
if path.startswith("/shot/"):
|
||||
name = path[len("/shot/"):]
|
||||
if ".." in name or "/" in name or "\\" in name:
|
||||
return b"", "text/plain; charset=utf-8"
|
||||
target = Path(__file__).resolve().parent / "site_shots" / name
|
||||
if target.is_file() and name.lower().endswith(
|
||||
(".png", ".jpg", ".jpeg", ".webp")):
|
||||
return target.read_bytes(), "image/png"
|
||||
return b"", "text/plain; charset=utf-8"
|
||||
|
||||
def do_GET(self): # noqa: N802
|
||||
RELAY.total_requests += 1
|
||||
path = self.path.split("?")[0]
|
||||
@@ -1510,6 +1556,12 @@ class Handler(BaseHTTPRequestHandler):
|
||||
实际渲染在 relay/admin.py —— 原来几百行 HTML/CSS/JS
|
||||
内联在这里的 f-string 里,改一处样式要在一堆转义花括号里翻,
|
||||
没法维护。拆出去之后这里只负责把数据递过去。
|
||||
|
||||
⚠ Content-Type 必须显式写 text/html。
|
||||
_send() 默认是 application/json;不传的话浏览器会把整页
|
||||
HTML 当纯文本显示出来 —— 用户看到的是一屏源码。
|
||||
(这个坑真踩了:改完只测了 HTTP 200 和字节数,
|
||||
没看响应头,结果页面在浏览器里是白的。)
|
||||
"""
|
||||
from admin import render_admin
|
||||
snap = RELAY.snapshot()
|
||||
@@ -1519,7 +1571,7 @@ class Handler(BaseHTTPRequestHandler):
|
||||
admin_path=ADMIN_PATH,
|
||||
codes=len(RELAY.codes),
|
||||
downloads_fn=_list_downloads,
|
||||
).encode("utf-8"))
|
||||
).encode("utf-8"), "text/html; charset=utf-8")
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Reference in New Issue
Block a user