main.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import logging
  2. from typing import List
  3. import httpx
  4. from fastapi import FastAPI, Request, Response, HTTPException
  5. from starlette.status import HTTP_502_BAD_GATEWAY
  6. from alien_gateway.config import settings
  7. app = FastAPI(
  8. title=f"{settings.PROJECT_NAME} - Gateway & Auth Service",
  9. version="1.0.0"
  10. )
  11. logger = logging.getLogger("alien_gateway")
  12. @app.get("/health")
  13. async def health():
  14. return {"service": "alien_gateway", "status": "ok"}
  15. # 此模块未来将承担 JWT 签发、权限校验中间件、路由聚合等核心功能
  16. @app.post("/auth/login")
  17. async def login():
  18. return {"message": "Auth logic here"}
  19. HOP_BY_HOP_HEADERS: List[str] = [
  20. "connection",
  21. "keep-alive",
  22. "proxy-authenticate",
  23. "proxy-authorization",
  24. "te",
  25. "trailers",
  26. "transfer-encoding",
  27. "upgrade",
  28. ]
  29. def _clean_headers(headers):
  30. """移除 hop-by-hop 头,避免转发问题。"""
  31. return {k: v for k, v in headers.items() if k.lower() not in HOP_BY_HOP_HEADERS}
  32. @app.api_route("/api/store/{full_path:path}", methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"])
  33. async def proxy_to_store(full_path: str, request: Request):
  34. """
  35. 简易网关:监听 33333 端口,将 /api/store/* 转发到 alien_store 服务。
  36. """
  37. target_url = f"{settings.STORE_BASE_URL}/api/store/{full_path}"
  38. client_ip = request.client.host if request.client else "-"
  39. # 读取请求体
  40. body = await request.body()
  41. # 过滤头部
  42. headers = _clean_headers(dict(request.headers))
  43. try:
  44. async with httpx.AsyncClient(timeout=30.0) as client:
  45. resp = await client.request(
  46. request.method,
  47. target_url,
  48. content=body,
  49. headers=headers,
  50. params=request.query_params,
  51. )
  52. except Exception as exc:
  53. logger.error("proxy to store failed ip=%s url=%s err=%s", client_ip, target_url, exc)
  54. raise HTTPException(status_code=HTTP_502_BAD_GATEWAY, detail="Upstream unavailable")
  55. # 返回下游响应
  56. return Response(
  57. content=resp.content,
  58. status_code=resp.status_code,
  59. headers=_clean_headers(resp.headers),
  60. media_type=resp.headers.get("content-type"),
  61. )
  62. if __name__ == "__main__":
  63. import uvicorn
  64. uvicorn.run(app, host="0.0.0.0", port=33333)