thinh-vu commited on
Commit
68bc6ef
·
verified ·
1 Parent(s): afa70eb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +38 -61
app.py CHANGED
@@ -3,11 +3,10 @@ from fastapi.middleware.cors import CORSMiddleware
3
  import httpx
4
  import json
5
  import random
6
- from typing import Dict, Any, Optional
7
 
8
  app = FastAPI(title="Vietcap Proxy for vnstock")
9
 
10
- # Thêm CORS middleware
11
  app.add_middleware(
12
  CORSMiddleware,
13
  allow_origins=["*"],
@@ -16,9 +15,6 @@ app.add_middleware(
16
  allow_headers=["*"],
17
  )
18
 
19
- TARGET_BASE = "https://trading.vietcap.com.vn"
20
-
21
- # Danh sách User-Agent để rotation
22
  USER_AGENTS = [
23
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
24
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
@@ -27,81 +23,65 @@ USER_AGENTS = [
27
  ]
28
 
29
  def get_random_headers() -> Dict[str, str]:
30
- """Tạo headers ngẫu nhiên để tránh bị phát hiện."""
31
  return {
32
  "accept": "application/json, text/plain, */*",
33
  "accept-language": "vi,en-US;q=0.9,en;q=0.8",
34
  "content-type": "application/json",
35
  "dnt": "1",
36
- "origin": "https://trading.vietcap.com.vn",
37
- "referer": "https://trading.vietcap.com.vn/price-board?filter-group=HOSE&filter-value=VN30&view-type=FLAT",
38
  "user-agent": random.choice(USER_AGENTS),
39
- "sec-fetch-dest": "empty",
40
- "sec-fetch-mode": "cors",
41
- "sec-fetch-site": "same-origin",
42
- "sec-ch-ua": '"Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"',
43
- "sec-ch-ua-mobile": "?0",
44
- "sec-ch-ua-platform": '"Windows"',
45
  "connection": "keep-alive"
46
  }
47
 
48
  @app.get("/")
49
  async def root():
50
- """Health check endpoint."""
51
- return {"status": "Vietcap Proxy is running", "target": TARGET_BASE}
52
 
53
  @app.post("/proxy")
54
  async def universal_proxy(request: Request):
55
  """
56
- Universal proxy endpoint tương thích với module api_client.
57
- Nhận JSON payload với url, headers, method, payload.
58
  """
59
  try:
60
- # Đọc request body
61
  body = await request.json()
62
-
63
- # Extract thông tin từ request
64
  target_url = body.get("url")
65
  method = body.get("method", "GET").upper()
66
- payload = body.get("payload")
67
- client_headers = body.get("headers", {})
68
-
 
69
  if not target_url:
70
  raise HTTPException(status_code=400, detail="Missing 'url' in request body")
71
 
72
- # Tạo headers cho request đến target
73
  proxy_headers = get_random_headers()
74
-
75
- # Merge với headers từ client (client headers có priority cao hơn)
76
- proxy_headers.update(client_headers)
77
-
78
- # Chuẩn bị request content
79
- request_content = None
80
- if payload:
81
- if isinstance(payload, str):
82
- request_content = payload
83
- else:
84
- request_content = json.dumps(payload)
85
-
86
- # Gửi request
87
- async with httpx.AsyncClient(timeout=30, follow_redirects=True) as client:
88
- if method == "GET":
89
- resp = await client.get(target_url, headers=proxy_headers)
90
- elif method == "POST":
91
- resp = await client.post(target_url, headers=proxy_headers, content=request_content)
92
- else:
93
- raise HTTPException(status_code=400, detail=f"Unsupported method: {method}")
94
-
95
- # Trả về response
96
  response_headers = {k: v for k, v in resp.headers.items()
97
- if k.lower() not in ("content-encoding", "transfer-encoding", "content-length")}
98
-
99
  return Response(
100
  content=resp.content,
101
  status_code=resp.status_code,
102
  headers=response_headers
103
  )
104
-
105
  except httpx.RequestError as exc:
106
  raise HTTPException(status_code=502, detail=f"Request failed: {str(exc)}")
107
  except json.JSONDecodeError:
@@ -109,25 +89,22 @@ async def universal_proxy(request: Request):
109
  except Exception as exc:
110
  raise HTTPException(status_code=500, detail=f"Internal error: {str(exc)}")
111
 
112
- @app.post("/vietcap/{path:path}")
 
113
  async def vietcap_proxy(path: str, request: Request):
114
- """
115
- Backward compatibility endpoint cho Vietcap API.
116
- """
117
- url = f"{TARGET_BASE}/{path}"
118
- body = await request.body()
119
-
120
  headers = get_random_headers()
121
-
 
122
  try:
123
  async with httpx.AsyncClient(timeout=30) as client:
124
- resp = await client.post(url, headers=headers, content=body)
125
  except httpx.RequestError as exc:
126
  raise HTTPException(status_code=502, detail=f"Không thể kết nối tới Vietcap: {exc}")
127
-
128
  return Response(
129
  content=resp.content,
130
  status_code=resp.status_code,
131
  headers={k: v for k, v in resp.headers.items()
132
  if k.lower() not in ("content-encoding", "transfer-encoding")}
133
- )
 
3
  import httpx
4
  import json
5
  import random
6
+ from typing import Dict, Any
7
 
8
  app = FastAPI(title="Vietcap Proxy for vnstock")
9
 
 
10
  app.add_middleware(
11
  CORSMiddleware,
12
  allow_origins=["*"],
 
15
  allow_headers=["*"],
16
  )
17
 
 
 
 
18
  USER_AGENTS = [
19
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
20
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
 
23
  ]
24
 
25
  def get_random_headers() -> Dict[str, str]:
 
26
  return {
27
  "accept": "application/json, text/plain, */*",
28
  "accept-language": "vi,en-US;q=0.9,en;q=0.8",
29
  "content-type": "application/json",
30
  "dnt": "1",
 
 
31
  "user-agent": random.choice(USER_AGENTS),
 
 
 
 
 
 
32
  "connection": "keep-alive"
33
  }
34
 
35
  @app.get("/")
36
  async def root():
37
+ return {"status": "Vietcap Proxy is running"}
 
38
 
39
  @app.post("/proxy")
40
  async def universal_proxy(request: Request):
41
  """
42
+ Universal proxy endpoint tương thích hoàn toàn với send_request:
43
+ Nhận JSON payload với url, headers, method, payload, params.
44
  """
45
  try:
 
46
  body = await request.json()
 
 
47
  target_url = body.get("url")
48
  method = body.get("method", "GET").upper()
49
+ payload = body.get("payload", None)
50
+ headers = body.get("headers", {}) or {}
51
+ params = body.get("params", None)
52
+
53
  if not target_url:
54
  raise HTTPException(status_code=400, detail="Missing 'url' in request body")
55
 
56
+ # Xây dựng headers hợp lý
57
  proxy_headers = get_random_headers()
58
+ proxy_headers.update(headers)
59
+
60
+ # Chuẩn bị các tham số cho httpx
61
+ request_kwargs = {
62
+ "url": target_url,
63
+ "headers": proxy_headers,
64
+ "timeout": 30,
65
+ "follow_redirects": True
66
+ }
67
+ if params:
68
+ request_kwargs["params"] = params
69
+ if method in ("POST", "PUT", "PATCH"):
70
+ if isinstance(payload, (dict, list)):
71
+ request_kwargs["content"] = json.dumps(payload)
72
+ elif payload is not None:
73
+ request_kwargs["content"] = payload
74
+
75
+ async with httpx.AsyncClient() as client:
76
+ resp = await client.request(method, **request_kwargs)
77
+
 
 
78
  response_headers = {k: v for k, v in resp.headers.items()
79
+ if k.lower() not in ("content-encoding", "transfer-encoding", "content-length")}
 
80
  return Response(
81
  content=resp.content,
82
  status_code=resp.status_code,
83
  headers=response_headers
84
  )
 
85
  except httpx.RequestError as exc:
86
  raise HTTPException(status_code=502, detail=f"Request failed: {str(exc)}")
87
  except json.JSONDecodeError:
 
89
  except Exception as exc:
90
  raise HTTPException(status_code=500, detail=f"Internal error: {str(exc)}")
91
 
92
+ # (Optional) Backward compatibility endpoint cho các client cũ
93
+ @app.api_route("/vietcap/{path:path}", methods=["GET", "POST", "PUT", "PATCH", "DELETE"])
94
  async def vietcap_proxy(path: str, request: Request):
95
+ url = f"https://trading.vietcap.com.vn/{path}"
96
+ method = request.method
 
 
 
 
97
  headers = get_random_headers()
98
+ headers.update(request.headers)
99
+ body = await request.body()
100
  try:
101
  async with httpx.AsyncClient(timeout=30) as client:
102
+ resp = await client.request(method, url, headers=headers, content=body)
103
  except httpx.RequestError as exc:
104
  raise HTTPException(status_code=502, detail=f"Không thể kết nối tới Vietcap: {exc}")
 
105
  return Response(
106
  content=resp.content,
107
  status_code=resp.status_code,
108
  headers={k: v for k, v in resp.headers.items()
109
  if k.lower() not in ("content-encoding", "transfer-encoding")}
110
+ )