sehsapneb commited on
Commit
ae8b72a
·
verified ·
1 Parent(s): 0dfba34

Create main.py

Browse files
Files changed (1) hide show
  1. main.py +65 -0
main.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import httpx
2
+ from fastapi import FastAPI, Request
3
+ from starlette.responses import HTMLResponse, StreamingResponse
4
+
5
+ app = FastAPI()
6
+ TARGET = "https://ewt360.com" # 目标站
7
+
8
+ # -------- 工具函数 ---------------------------------------------------------
9
+ INJECT_JS = """
10
+ <script>
11
+ function clickZa() {
12
+ document.querySelectorAll('button').forEach(btn => {
13
+ if (btn.textContent.trim() === '在') btn.click();
14
+ });
15
+ }
16
+ document.addEventListener('DOMContentLoaded', clickZa);
17
+
18
+ // 处理 SPA / 懒加载:DOM 变化时再检测一次
19
+ new MutationObserver(clickZa).observe(document.documentElement, {
20
+ childList: true,
21
+ subtree: true
22
+ });
23
+ </script>
24
+ """
25
+
26
+ def _inject(html: str) -> str:
27
+ """把注入脚本塞到 </body> 前;若无 </body> 则直接追加"""
28
+ return html.replace("</body>", INJECT_JS + "</body>") if "</body>" in html else html + INJECT_JS
29
+
30
+ async def _fetch_upstream(req: Request, path: str) -> httpx.Response:
31
+ """把客户端请求转发到目标站"""
32
+ async with httpx.AsyncClient(follow_redirects=True, timeout=30) as client:
33
+ upstream_url = f"{TARGET}/{path}"
34
+ headers = {k: v for k, v in req.headers.items()
35
+ if k.lower() not in {"host", "content-length", "accept-encoding", "connection"}}
36
+ return await client.request(
37
+ req.method,
38
+ upstream_url,
39
+ params=req.query_params,
40
+ content=await req.body(),
41
+ headers=headers
42
+ )
43
+
44
+ # -------- 统一代理入口 ------------------------------------------------------
45
+ @app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "PATCH", "DELETE"])
46
+ async def proxy(path: str, request: Request):
47
+ upstream = await _fetch_upstream(request, path)
48
+ ct = upstream.headers.get("content-type", "")
49
+
50
+ # 对 HTML 页面做脚本注入
51
+ if "text/html" in ct:
52
+ html = _inject(upstream.text)
53
+ # 过滤掉与内容长度 / 压缩相关的头,避免浏览器警告
54
+ safe_headers = {k: v for k, v in upstream.headers.items()
55
+ if k.lower() not in {"content-length", "content-encoding"}}
56
+ return HTMLResponse(html, status_code=upstream.status_code, headers=safe_headers)
57
+
58
+ # 其他资源直接流式返回(JS / CSS / 图片等)
59
+ return StreamingResponse(
60
+ upstream.aiter_bytes(),
61
+ status_code=upstream.status_code,
62
+ media_type=ct or None,
63
+ headers={k: v for k, v in upstream.headers.items()
64
+ if k.lower() not in {"content-length", "content-encoding"}}
65
+ )