5d1f34524e
http.server 的 guess_type() 从不附带 charset,直接导航到 .cpp/.md 等 文本文件时浏览器猜编码猜错,中文注释显示乱码。Content-Type 统一补 charset=utf-8。
48 lines
1.8 KiB
Python
Executable File
48 lines
1.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""本地起 HTTP 服务播放教案幻灯片(离线可用)。
|
|
用法:python3 docs/teaching/serve.py [端口,默认 8000]
|
|
浏览器打开 http://localhost:<端口>/docs/teaching/slides/index.html
|
|
|
|
只绑定 127.0.0.1(不对局域网暴露)——仓库根目录含 .env(wiki 登录凭据),
|
|
必须避免整个仓库被同一 Wi-Fi/局域网上的其他设备访问到。
|
|
"""
|
|
import http.server
|
|
import mimetypes
|
|
import os
|
|
import socketserver
|
|
import sys
|
|
|
|
# 幻灯片里点击的源码链接(.c/.cpp/.py/.md 等)需要以纯文本显示,而不是被当成
|
|
# 未知二进制触发下载——默认 mimetypes 对 .cpp/.c 等会猜成 text/x-csrc 之类,
|
|
# 浏览器不会内联渲染,这里统一覆盖成 text/plain。
|
|
for ext in (".c", ".cpp", ".h", ".hpp", ".cc", ".qrc", ".py", ".md"):
|
|
mimetypes.add_type("text/plain", ext)
|
|
|
|
repo_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
os.chdir(repo_root)
|
|
|
|
try:
|
|
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8000
|
|
except ValueError:
|
|
print(f"用法:python3 {sys.argv[0]} [端口号]")
|
|
sys.exit(1)
|
|
|
|
|
|
class ReuseAddrTCPServer(socketserver.TCPServer):
|
|
allow_reuse_address = True
|
|
|
|
|
|
class Utf8RequestHandler(http.server.SimpleHTTPRequestHandler):
|
|
# http.server 的 guess_type() 从不附带 charset——中文源码/文档被当成
|
|
# 无编码信息的 text/plain 返回,浏览器直接导航时会猜错编码变成乱码。
|
|
def guess_type(self, path):
|
|
ctype = super().guess_type(path)
|
|
if ctype.startswith("text/") and "charset=" not in ctype:
|
|
ctype += "; charset=utf-8"
|
|
return ctype
|
|
|
|
|
|
with ReuseAddrTCPServer(("127.0.0.1", port), Utf8RequestHandler) as httpd:
|
|
print(f"Serving {repo_root} at http://localhost:{port}/docs/teaching/slides/index.html")
|
|
httpd.serve_forever()
|