|
@@ -0,0 +1,45 @@
|
|
|
|
|
+#!/usr/bin/env python3
|
|
|
|
|
+"""极简静态服务器(带 SPA 路由回退)—— 用户空间,CentOS 自带 Python 3.6 即可。
|
|
|
|
|
+
|
|
|
|
|
+托管前端构建产物(deploy 分支的 dist),供内网访问。客户端路由(如
|
|
|
|
|
+/behavior/funnel/group)刷新时回退到 index.html,避免 404。
|
|
|
|
|
+兼容 Python 3.6(不用 3.7+ 的 `directory=` 参数,改 os.chdir)。
|
|
|
|
|
+
|
|
|
|
|
+用法:
|
|
|
|
|
+ python3 serve.py <静态目录> [端口]
|
|
|
|
|
+例:
|
|
|
|
|
+ nohup python3 ~/serve-hs.py ~/hs-data 6666 > ~/hs-web.log 2>&1 &
|
|
|
|
|
+"""
|
|
|
|
|
+import os
|
|
|
|
|
+import sys
|
|
|
|
|
+from http.server import SimpleHTTPRequestHandler
|
|
|
|
|
+from socketserver import ThreadingTCPServer
|
|
|
|
|
+
|
|
|
|
|
+ROOT = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else ".")
|
|
|
|
|
+PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 6666
|
|
|
|
|
+os.chdir(ROOT)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class SpaHandler(SimpleHTTPRequestHandler):
|
|
|
|
|
+ def do_GET(self):
|
|
|
|
|
+ # 路径不是真实文件 → 回退到 index.html(SPA 客户端路由)。
|
|
|
|
|
+ rel = self.path.split("?", 1)[0].split("#", 1)[0].lstrip("/")
|
|
|
|
|
+ if rel and not os.path.isfile(os.path.join(ROOT, rel)):
|
|
|
|
|
+ self.path = "/index.html"
|
|
|
|
|
+ return SimpleHTTPRequestHandler.do_GET(self)
|
|
|
|
|
+
|
|
|
|
|
+ def end_headers(self):
|
|
|
|
|
+ # index.html 不缓存(构建产物自带 hash,可长缓存)。
|
|
|
|
|
+ if self.path in ("/", "/index.html"):
|
|
|
|
|
+ self.send_header("Cache-Control", "no-cache")
|
|
|
|
|
+ SimpleHTTPRequestHandler.end_headers(self)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class Server(ThreadingTCPServer):
|
|
|
|
|
+ allow_reuse_address = True
|
|
|
|
|
+ daemon_threads = True
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+if __name__ == "__main__":
|
|
|
|
|
+ print("serving %s on 0.0.0.0:%d (SPA fallback)" % (ROOT, PORT))
|
|
|
|
|
+ Server(("0.0.0.0", PORT), SpaHandler).serve_forever()
|