|
|
@@ -1,4 +1,8 @@
|
|
|
-from fastapi import FastAPI
|
|
|
+import logging
|
|
|
+from typing import List
|
|
|
+import httpx
|
|
|
+from fastapi import FastAPI, Request, Response, HTTPException
|
|
|
+from starlette.status import HTTP_502_BAD_GATEWAY
|
|
|
from alien_gateway.config import settings
|
|
|
|
|
|
app = FastAPI(
|
|
|
@@ -6,6 +10,8 @@ app = FastAPI(
|
|
|
version="1.0.0"
|
|
|
)
|
|
|
|
|
|
+logger = logging.getLogger("alien_gateway")
|
|
|
+
|
|
|
@app.get("/health")
|
|
|
async def health():
|
|
|
return {"service": "alien_gateway", "status": "ok"}
|
|
|
@@ -15,6 +21,59 @@ async def health():
|
|
|
async def login():
|
|
|
return {"message": "Auth logic here"}
|
|
|
|
|
|
+
|
|
|
+HOP_BY_HOP_HEADERS: List[str] = [
|
|
|
+ "connection",
|
|
|
+ "keep-alive",
|
|
|
+ "proxy-authenticate",
|
|
|
+ "proxy-authorization",
|
|
|
+ "te",
|
|
|
+ "trailers",
|
|
|
+ "transfer-encoding",
|
|
|
+ "upgrade",
|
|
|
+]
|
|
|
+
|
|
|
+
|
|
|
+def _clean_headers(headers):
|
|
|
+ """移除 hop-by-hop 头,避免转发问题。"""
|
|
|
+ return {k: v for k, v in headers.items() if k.lower() not in HOP_BY_HOP_HEADERS}
|
|
|
+
|
|
|
+
|
|
|
+@app.api_route("/api/store/{full_path:path}", methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"])
|
|
|
+async def proxy_to_store(full_path: str, request: Request):
|
|
|
+ """
|
|
|
+ 简易网关:监听 33333 端口,将 /api/store/* 转发到 alien_store 服务。
|
|
|
+ """
|
|
|
+ target_url = f"{settings.STORE_BASE_URL}/api/store/{full_path}"
|
|
|
+ client_ip = request.client.host if request.client else "-"
|
|
|
+
|
|
|
+ # 读取请求体
|
|
|
+ body = await request.body()
|
|
|
+
|
|
|
+ # 过滤头部
|
|
|
+ headers = _clean_headers(dict(request.headers))
|
|
|
+
|
|
|
+ try:
|
|
|
+ async with httpx.AsyncClient(timeout=30.0) as client:
|
|
|
+ resp = await client.request(
|
|
|
+ request.method,
|
|
|
+ target_url,
|
|
|
+ content=body,
|
|
|
+ headers=headers,
|
|
|
+ params=request.query_params,
|
|
|
+ )
|
|
|
+ except Exception as exc:
|
|
|
+ logger.error("proxy to store failed ip=%s url=%s err=%s", client_ip, target_url, exc)
|
|
|
+ raise HTTPException(status_code=HTTP_502_BAD_GATEWAY, detail="Upstream unavailable")
|
|
|
+
|
|
|
+ # 返回下游响应
|
|
|
+ return Response(
|
|
|
+ content=resp.content,
|
|
|
+ status_code=resp.status_code,
|
|
|
+ headers=_clean_headers(resp.headers),
|
|
|
+ media_type=resp.headers.get("content-type"),
|
|
|
+ )
|
|
|
+
|
|
|
if __name__ == "__main__":
|
|
|
import uvicorn
|
|
|
- uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
|
+ uvicorn.run(app, host="0.0.0.0", port=33333)
|