Deploy commited on
Commit
7d1f8cf
·
1 Parent(s): d9fc91a

Deploy proxy

Browse files
Files changed (2) hide show
  1. app.py +72 -13
  2. requirements.txt +1 -1
app.py CHANGED
@@ -1,19 +1,39 @@
1
  from fastapi import FastAPI, Request, Response
2
- from fastapi.responses import JSONResponse
3
- import requests
4
  import os
 
 
5
 
6
  app = FastAPI()
7
 
 
 
 
 
 
 
 
 
8
  @app.get("/")
 
9
  async def root():
10
  return {"status": "ok", "service": "HTTP Proxy Node"}
11
 
 
 
 
 
 
12
  @app.post("/api/proxy")
13
  async def proxy(request: Request):
14
  """标准 HTTP 代理 API"""
 
 
 
15
  try:
16
  # 解析请求
 
17
  data = await request.json()
18
 
19
  target_url = data.get("url")
@@ -21,6 +41,8 @@ async def proxy(request: Request):
21
  headers = data.get("headers", {})
22
  body = data.get("body")
23
 
 
 
24
  if not target_url:
25
  return JSONResponse(
26
  {"error": "Missing url parameter"},
@@ -35,24 +57,61 @@ async def proxy(request: Request):
35
  except:
36
  body = body.encode('utf-8')
37
 
38
- # 发送请求
39
- resp = requests.request(
40
- method=method,
41
- url=target_url,
42
- headers=headers,
43
- data=body,
44
- timeout=30,
45
- allow_redirects=True
46
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- # 返回响应
49
  return Response(
50
  content=resp.content,
51
  status_code=resp.status_code,
52
- headers=dict(resp.headers)
53
  )
54
 
55
  except Exception as e:
 
56
  return JSONResponse(
57
  {"error": str(e)},
58
  status_code=500
 
1
  from fastapi import FastAPI, Request, Response
2
+ from fastapi.responses import JSONResponse, PlainTextResponse
3
+ import httpx
4
  import os
5
+ import sys
6
+ from collections import deque
7
 
8
  app = FastAPI()
9
 
10
+ # 内存日志队列(最多保存1000条)
11
+ log_buffer = deque(maxlen=1000)
12
+
13
+ def log_message(msg):
14
+ """记录日志到内存和标准输出"""
15
+ log_buffer.append(msg)
16
+ print(msg, flush=True)
17
+
18
  @app.get("/")
19
+ @app.head("/")
20
  async def root():
21
  return {"status": "ok", "service": "HTTP Proxy Node"}
22
 
23
+ @app.get("/logs")
24
+ async def get_logs():
25
+ """获取最近的日志"""
26
+ return PlainTextResponse("\n".join(log_buffer))
27
+
28
  @app.post("/api/proxy")
29
  async def proxy(request: Request):
30
  """标准 HTTP 代理 API"""
31
+ import time
32
+ start_time = time.time()
33
+
34
  try:
35
  # 解析请求
36
+ parse_start = time.time()
37
  data = await request.json()
38
 
39
  target_url = data.get("url")
 
41
  headers = data.get("headers", {})
42
  body = data.get("body")
43
 
44
+ log_message(f"[PROXY] {method} {target_url[:80]} - parse: {(time.time()-parse_start)*1000:.0f}ms")
45
+
46
  if not target_url:
47
  return JSONResponse(
48
  {"error": "Missing url parameter"},
 
57
  except:
58
  body = body.encode('utf-8')
59
 
60
+ # 发送请求(异步)
61
+ fetch_start = time.time()
62
+ log_message(f"[FETCH_START] {method} {target_url[:80]}")
63
+
64
+ try:
65
+ # 设置更详细的超时
66
+ timeout_config = httpx.Timeout(
67
+ connect=10.0, # 连接超时
68
+ read=30.0, # 读取超时
69
+ write=10.0, # 写入超时
70
+ pool=10.0 # 连接池超时
71
+ )
72
+
73
+ async with httpx.AsyncClient(timeout=timeout_config, follow_redirects=True) as client:
74
+ resp = await client.request(
75
+ method=method,
76
+ url=target_url,
77
+ headers=headers,
78
+ content=body
79
+ )
80
+
81
+ log_message(f"[FETCH] {resp.status_code} {len(resp.content)} bytes - {(time.time()-fetch_start)*1000:.0f}ms")
82
+ except httpx.TimeoutException as e:
83
+ error_msg = f"{type(e).__name__}: {str(e) or repr(e)}"
84
+ log_message(f"[FETCH_TIMEOUT] {error_msg} - {(time.time()-fetch_start)*1000:.0f}ms")
85
+ raise
86
+ except httpx.HTTPError as e:
87
+ error_msg = f"{type(e).__name__}: {str(e) or repr(e)}"
88
+ log_message(f"[FETCH_HTTP_ERROR] {error_msg} - {(time.time()-fetch_start)*1000:.0f}ms")
89
+ raise
90
+ except Exception as fetch_error:
91
+ error_msg = f"{type(fetch_error).__name__}: {str(fetch_error) or repr(fetch_error)}"
92
+ log_message(f"[FETCH_ERROR] {error_msg} - {(time.time()-fetch_start)*1000:.0f}ms")
93
+ import traceback
94
+ log_message(f"[TRACEBACK] {traceback.format_exc()}")
95
+ raise
96
+
97
+ # 返回响应(过滤掉会冲突的 headers)
98
+ response_headers = {}
99
+ for k, v in resp.headers.items():
100
+ k_lower = k.lower()
101
+ # 跳过这些 headers,让 FastAPI 自动处理
102
+ if k_lower not in ['content-length', 'content-encoding', 'transfer-encoding']:
103
+ response_headers[k] = v
104
+
105
+ log_message(f"[DONE] Total: {(time.time()-start_time)*1000:.0f}ms")
106
 
 
107
  return Response(
108
  content=resp.content,
109
  status_code=resp.status_code,
110
+ headers=response_headers
111
  )
112
 
113
  except Exception as e:
114
+ log_message(f"[ERROR] {str(e)} - {(time.time()-start_time)*1000:.0f}ms")
115
  return JSONResponse(
116
  {"error": str(e)},
117
  status_code=500
requirements.txt CHANGED
@@ -1,3 +1,3 @@
1
  fastapi
2
  uvicorn
3
- requests
 
1
  fastapi
2
  uvicorn
3
+ httpx