增加了proxy配置
parent
72c9b3a243
commit
0139303b6a
|
|
@ -18,6 +18,9 @@ REDIS_MAX_CONNECTIONS=50
|
|||
# ======================
|
||||
# Application Configuration
|
||||
# ======================
|
||||
# JWT Secret Key (IMPORTANT: Change this in production!)
|
||||
JWT_SECRET_KEY=your-production-secret-key-change-this-to-random-string
|
||||
|
||||
# CORS - Support both internal IP access and external domain
|
||||
# Format: comma-separated list of origins
|
||||
# Examples:
|
||||
|
|
@ -45,6 +48,15 @@ CACHE_TTL_DAYS=3
|
|||
# ======================
|
||||
MAX_UPLOAD_SIZE=10485760
|
||||
|
||||
# ======================
|
||||
# Proxy Configuration
|
||||
# ======================
|
||||
# HTTP Proxy for accessing NASA JPL Horizons API (optional)
|
||||
# Format: http://host:port or https://host:port
|
||||
# Example: HTTP_PROXY=http://192.168.124.203:20171
|
||||
HTTP_PROXY=http://192.168.124.203:20171
|
||||
HTTPS_PROXY=http://192.168.124.203:20171
|
||||
|
||||
# ======================
|
||||
# Data Path Configuration
|
||||
# ======================
|
||||
|
|
|
|||
|
|
@ -133,6 +133,10 @@ cosmo/
|
|||
# 修改数据库密码(必须)
|
||||
DATABASE_PASSWORD=your_secure_password_here
|
||||
|
||||
# 修改 JWT Secret Key(必须,用于生成和验证 JWT token)
|
||||
# 使用随机字符串,至少 32 位
|
||||
JWT_SECRET_KEY=your-random-secret-key-at-least-32-characters-long
|
||||
|
||||
# 修改 CORS 配置(支持内网 IP 和外网域名访问)
|
||||
# 方式 1: 允许所有来源(开发/测试环境)
|
||||
CORS_ORIGINS=*
|
||||
|
|
@ -152,6 +156,13 @@ CORS_ORIGINS=http://192.168.1.100,http://your-domain.com,https://your-domain.com
|
|||
|
||||
# 如果前后端分离部署在不同服务器,才需要设置完整地址:
|
||||
# VITE_API_BASE_URL=http://your-domain.com/api
|
||||
|
||||
# HTTP 代理配置(用于访问 NASA JPL Horizons API)
|
||||
# 如果服务器在中国境内无法直接访问 NASA API,需要配置 HTTP 代理
|
||||
# 格式:http://host:port 或 https://host:port
|
||||
# 示例:HTTP_PROXY=http://192.168.124.203:20171
|
||||
HTTP_PROXY=
|
||||
HTTPS_PROXY=
|
||||
```
|
||||
|
||||
**重要说明**:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,163 @@
|
|||
# HTTP 代理配置指南
|
||||
|
||||
## 问题背景
|
||||
|
||||
在中国境内部署 Cosmo 时,后端服务需要访问 NASA JPL Horizons API 来获取天体数据,但由于网络限制,直接访问可能会超时或失败。
|
||||
|
||||
## 解决方案
|
||||
|
||||
配置 HTTP 代理来访问 NASA API。
|
||||
|
||||
## 配置步骤
|
||||
|
||||
### 1. 在 `.env.production` 中配置代理
|
||||
|
||||
编辑 `/Users/jiliu/WorkSpace/cosmo/.env.production` 文件,添加代理配置:
|
||||
|
||||
```bash
|
||||
# HTTP 代理配置(用于访问 NASA JPL Horizons API)
|
||||
# 格式:http://host:port
|
||||
HTTP_PROXY=http://192.168.124.203:20171
|
||||
HTTPS_PROXY=http://192.168.124.203:20171
|
||||
```
|
||||
|
||||
**注意**:
|
||||
- 代理地址格式必须包含协议前缀(`http://` 或 `https://`)
|
||||
- 如果您的代理服务器只监听 HTTP,两个配置都使用 `http://`
|
||||
- 确保代理服务器在部署的服务器上可以访问(192.168.124.203:20171)
|
||||
|
||||
### 2. 重启后端服务
|
||||
|
||||
配置修改后需要重启后端服务才能生效:
|
||||
|
||||
```bash
|
||||
# 在部署服务器上执行
|
||||
cd /path/to/cosmo
|
||||
./deploy.sh --restart
|
||||
```
|
||||
|
||||
或者使用 Docker Compose:
|
||||
|
||||
```bash
|
||||
docker-compose restart backend
|
||||
```
|
||||
|
||||
## 工作原理
|
||||
|
||||
### 1. httpx 代理配置
|
||||
|
||||
后端使用 `httpx` 库直接访问 NASA API(`get_object_data_raw` 方法)。代理通过 `httpx.AsyncClient` 的 `proxies` 参数传递:
|
||||
|
||||
```python
|
||||
client_kwargs = {"timeout": 5.0}
|
||||
if settings.proxy_dict:
|
||||
client_kwargs["proxies"] = settings.proxy_dict
|
||||
# proxies = {"http://": "http://192.168.124.203:20171",
|
||||
# "https://": "http://192.168.124.203:20171"}
|
||||
|
||||
async with httpx.AsyncClient(**client_kwargs) as client:
|
||||
response = await client.get(url, params=params)
|
||||
```
|
||||
|
||||
### 2. astroquery 代理配置
|
||||
|
||||
`astroquery` 库(用于 `get_body_positions` 方法)通过标准环境变量使用代理:
|
||||
|
||||
```python
|
||||
if settings.http_proxy:
|
||||
os.environ['HTTP_PROXY'] = settings.http_proxy
|
||||
if settings.https_proxy:
|
||||
os.environ['HTTPS_PROXY'] = settings.https_proxy
|
||||
```
|
||||
|
||||
## 验证配置
|
||||
|
||||
### 1. 检查日志
|
||||
|
||||
配置代理后,启动服务时会在日志中看到:
|
||||
|
||||
```
|
||||
INFO - Set HTTP_PROXY for astroquery: http://192.168.124.203:20171
|
||||
INFO - Set HTTPS_PROXY for astroquery: http://192.168.124.203:20171
|
||||
```
|
||||
|
||||
访问 NASA API 时会看到:
|
||||
|
||||
```
|
||||
INFO - Using proxy for NASA API: {'http://': 'http://192.168.124.203:20171', 'https://': 'http://192.168.124.203:20171'}
|
||||
INFO - Fetching raw data for body 10
|
||||
```
|
||||
|
||||
### 2. 测试 API 访问
|
||||
|
||||
在前端点击天体的 "JPL Horizons" 按钮,查看是否能成功获取数据。
|
||||
|
||||
或者直接访问后端 API:
|
||||
|
||||
```bash
|
||||
curl http://your-server-ip/api/nasa/object/10
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 代理地址格式错误
|
||||
|
||||
❌ **错误**:
|
||||
```bash
|
||||
HTTP_PROXY=192.168.124.203:20171 # 缺少协议前缀
|
||||
```
|
||||
|
||||
✅ **正确**:
|
||||
```bash
|
||||
HTTP_PROXY=http://192.168.124.203:20171
|
||||
```
|
||||
|
||||
### 2. 代理服务器无法访问
|
||||
|
||||
确保代理服务器在部署服务器上可以访问:
|
||||
|
||||
```bash
|
||||
# 在部署服务器上测试
|
||||
curl -x http://192.168.124.203:20171 https://ssd.jpl.nasa.gov/api/horizons.api
|
||||
```
|
||||
|
||||
### 3. 仍然超时
|
||||
|
||||
如果配置代理后仍然超时,检查:
|
||||
|
||||
1. 代理服务器是否运行正常
|
||||
2. 代理服务器是否允许访问 `ssd.jpl.nasa.gov`
|
||||
3. 防火墙是否阻止了连接
|
||||
|
||||
### 4. 日志中没有代理信息
|
||||
|
||||
如果日志中没有 "Using proxy" 信息,检查:
|
||||
|
||||
1. `.env.production` 文件是否正确配置
|
||||
2. 是否重启了服务
|
||||
3. Docker 容器是否正确加载了环境变量:
|
||||
|
||||
```bash
|
||||
docker-compose exec backend env | grep PROXY
|
||||
```
|
||||
|
||||
## 不需要代理的情况
|
||||
|
||||
如果您的服务器可以直接访问 NASA API(例如:海外服务器),只需将代理配置留空即可:
|
||||
|
||||
```bash
|
||||
HTTP_PROXY=
|
||||
HTTPS_PROXY=
|
||||
```
|
||||
|
||||
## 相关文件
|
||||
|
||||
- **配置**: `backend/app/config.py` - Settings 类中的 `http_proxy`, `https_proxy`, `proxy_dict`
|
||||
- **使用**: `backend/app/services/horizons.py` - HorizonsService 类
|
||||
- **环境变量**: `.env.production` - HTTP_PROXY, HTTPS_PROXY
|
||||
|
||||
## 参考链接
|
||||
|
||||
- [httpx Proxies Documentation](https://www.python-httpx.org/advanced/#http-proxying)
|
||||
- [NASA JPL Horizons API](https://ssd-api.jpl.nasa.gov/doc/horizons.html)
|
||||
- [astroquery Documentation](https://astroquery.readthedocs.io/)
|
||||
|
|
@ -64,6 +64,22 @@ class Settings(BaseSettings):
|
|||
upload_dir: str = "upload"
|
||||
max_upload_size: int = 10485760 # 10MB
|
||||
|
||||
# Proxy settings (for accessing NASA JPL Horizons API in China)
|
||||
http_proxy: str = ""
|
||||
https_proxy: str = ""
|
||||
|
||||
@property
|
||||
def proxy_dict(self) -> dict[str, str] | None:
|
||||
"""Get proxy configuration as a dictionary for httpx"""
|
||||
if self.http_proxy or self.https_proxy:
|
||||
proxies = {}
|
||||
if self.http_proxy:
|
||||
proxies["http://"] = self.http_proxy
|
||||
if self.https_proxy:
|
||||
proxies["https://"] = self.https_proxy
|
||||
return proxies
|
||||
return None
|
||||
|
||||
@property
|
||||
def database_url(self) -> str:
|
||||
"""Construct database URL for SQLAlchemy"""
|
||||
|
|
|
|||
|
|
@ -34,11 +34,19 @@ from app.services.cache_preheat import preheat_all_caches
|
|||
from app.database import close_db
|
||||
|
||||
# Configure logging
|
||||
# Set root logger to WARNING in production, INFO in development
|
||||
log_level = logging.INFO if settings.jwt_secret_key == "your-secret-key-change-this-in-production" else logging.WARNING
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
level=log_level,
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
)
|
||||
|
||||
# Reduce noise from specific loggers in production
|
||||
if log_level == logging.WARNING:
|
||||
logging.getLogger("app.services.cache").setLevel(logging.ERROR)
|
||||
logging.getLogger("app.services.redis_cache").setLevel(logging.ERROR)
|
||||
logging.getLogger("app.api.celestial_position").setLevel(logging.WARNING)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@ from astropy.time import Time
|
|||
import logging
|
||||
import re
|
||||
import httpx
|
||||
import os
|
||||
|
||||
from app.models.celestial import Position, CelestialBody
|
||||
from app.config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -20,6 +22,15 @@ class HorizonsService:
|
|||
"""Initialize the service"""
|
||||
self.location = "@sun" # Heliocentric coordinates
|
||||
|
||||
# Set proxy for astroquery if configured
|
||||
# astroquery uses standard HTTP_PROXY and HTTPS_PROXY environment variables
|
||||
if settings.http_proxy:
|
||||
os.environ['HTTP_PROXY'] = settings.http_proxy
|
||||
logger.info(f"Set HTTP_PROXY for astroquery: {settings.http_proxy}")
|
||||
if settings.https_proxy:
|
||||
os.environ['HTTPS_PROXY'] = settings.https_proxy
|
||||
logger.info(f"Set HTTPS_PROXY for astroquery: {settings.https_proxy}")
|
||||
|
||||
async def get_object_data_raw(self, body_id: str) -> str:
|
||||
"""
|
||||
Get raw object data (terminal style text) from Horizons
|
||||
|
|
@ -33,7 +44,7 @@ class HorizonsService:
|
|||
url = "https://ssd.jpl.nasa.gov/api/horizons.api"
|
||||
# Ensure ID is quoted for COMMAND
|
||||
cmd_val = f"'{body_id}'" if not body_id.startswith("'") else body_id
|
||||
|
||||
|
||||
params = {
|
||||
"format": "text",
|
||||
"COMMAND": cmd_val,
|
||||
|
|
@ -44,10 +55,15 @@ class HorizonsService:
|
|||
}
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient() as client:
|
||||
# Configure proxy if available
|
||||
client_kwargs = {"timeout": 5.0}
|
||||
if settings.proxy_dict:
|
||||
client_kwargs["proxies"] = settings.proxy_dict
|
||||
logger.info(f"Using proxy for NASA API: {settings.proxy_dict}")
|
||||
|
||||
async with httpx.AsyncClient(**client_kwargs) as client:
|
||||
logger.info(f"Fetching raw data for body {body_id}")
|
||||
# Reduced timeout for China network (NASA JPL may be blocked)
|
||||
response = await client.get(url, params=params, timeout=5.0)
|
||||
response = await client.get(url, params=params)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"NASA API returned status {response.status_code}")
|
||||
|
|
|
|||
Loading…
Reference in New Issue