fix: enhance cors origin configuration
This commit is contained in:
@@ -2,6 +2,7 @@ NEXT_PUBLIC_API_BASE_URL=http://127.0.0.1:8000
|
||||
API_HOST=0.0.0.0
|
||||
API_PORT=8000
|
||||
API_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
|
||||
API_CORS_ORIGIN_REGEX=
|
||||
DATABASE_URL=postgresql+psycopg://fquiz:fquiz@db:5432/fquiz
|
||||
FILE_VFS_ROOT=./data/vfs
|
||||
JWT_SECRET_KEY=change-this-in-production
|
||||
|
||||
@@ -155,6 +155,7 @@ jobs:
|
||||
API_HOST: ${API_HOST:-0.0.0.0}
|
||||
API_PORT: ${API_PORT:-8000}
|
||||
API_CORS_ORIGINS: ${API_CORS_ORIGINS:-http://localhost:3000,http://127.0.0.1:3000}
|
||||
API_CORS_ORIGIN_REGEX: ${API_CORS_ORIGIN_REGEX:-}
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql+psycopg://fquiz:fquiz@db:5432/fquiz}
|
||||
JWT_SECRET_KEY: ${JWT_SECRET_KEY:-change-this-in-production}
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: ${ACCESS_TOKEN_EXPIRE_MINUTES:-15}
|
||||
@@ -197,6 +198,7 @@ jobs:
|
||||
API_HOST=0.0.0.0
|
||||
API_PORT=8000
|
||||
API_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
|
||||
API_CORS_ORIGIN_REGEX=
|
||||
DATABASE_URL=postgresql+psycopg://fquiz:fquiz@db:5432/fquiz
|
||||
JWT_SECRET_KEY=change-this-in-production
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES=15
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
- `app.models` 包初始化需预加载全部模型模块,确保字符串关系(如 `"AuditLog"`)在启动阶段可解析。
|
||||
- 部署 compose 中 DB 镜像应通过 `POSTGRES_IMAGE` 可配置,默认使用镜像站的 pgvector 镜像(`docker.m.daocloud.io/pgvector/pgvector:pg16`)。
|
||||
- 宿主机 DB 暴露端口统一走 `POSTGRES_PORT`(默认 `5433`),用于规避与宿主机已有 PostgreSQL(常见 `5432`)冲突;容器内连接仍保持 `db:5432`。
|
||||
- CORS 来源控制采用“双轨配置”:`API_CORS_ORIGINS`(精确列表)+ `API_CORS_ORIGIN_REGEX`(正则,可选);`API_CORS_ORIGINS` 支持 `*` 和通配符域名并在后端转换为 `allow_origin_regex`。
|
||||
- GitHub Actions 使用 `appleboy/ssh-action` 部署时,慢网环境需显式设置 `command_timeout`(建议 `45m`)并为 `docker compose pull` 增加重试,避免出现 `Run Command Timeout` 直接中断发布。
|
||||
|
||||
## 前端视觉口径(2026-04-12)
|
||||
|
||||
@@ -124,4 +124,8 @@ npm run lint:web
|
||||
说明:
|
||||
- `NEXT_PUBLIC_API_BASE_URL` 在 Next.js 中是构建期注入;如果修改该值,需要重新执行 `docker compose up --build`。
|
||||
- 若使用 Docker Compose,默认 `DATABASE_URL` 指向容器内 `db` 服务(PostgreSQL)。
|
||||
- 若出现跨域(CORS)错误,请在 `.env` 配置:
|
||||
- `API_CORS_ORIGINS`:精确来源列表(逗号分隔),如 `https://admin.example.com,http://localhost:3000`
|
||||
- `API_CORS_ORIGIN_REGEX`:来源正则(可选),如 `https://.*\\.example\\.com`
|
||||
- 支持在 `API_CORS_ORIGINS` 中使用通配符(如 `https://*.example.com`)或 `*`(仅建议开发调试)
|
||||
- 默认镜像源已配置为 `docker.m.daocloud.io`,并默认使用 `pgvector` 镜像;如你网络环境可直连 Docker Hub,可在 `.env` 中覆盖 `POSTGRES_IMAGE / PYTHON_BASE_IMAGE / NODE_BASE_IMAGE`。
|
||||
|
||||
+34
-5
@@ -1,4 +1,5 @@
|
||||
from functools import lru_cache
|
||||
import re
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import field_validator
|
||||
@@ -11,6 +12,7 @@ class Settings(BaseSettings):
|
||||
api_host: str = "0.0.0.0"
|
||||
api_port: int = 8000
|
||||
api_cors_origins: str = "http://localhost:3000,http://127.0.0.1:3000"
|
||||
api_cors_origin_regex: str | None = None
|
||||
|
||||
database_url: str = "sqlite:///./fquiz.db"
|
||||
file_vfs_root: str = "./data/vfs"
|
||||
@@ -45,11 +47,38 @@ class Settings(BaseSettings):
|
||||
|
||||
@property
|
||||
def cors_origins(self) -> list[str]:
|
||||
return [
|
||||
origin.strip()
|
||||
for origin in self.api_cors_origins.split(",")
|
||||
if origin.strip()
|
||||
]
|
||||
origins: list[str] = []
|
||||
for origin in self.api_cors_origins.split(","):
|
||||
normalized = origin.strip()
|
||||
if not normalized:
|
||||
continue
|
||||
if normalized == "*" or "*" in normalized:
|
||||
continue
|
||||
origins.append(normalized)
|
||||
return origins
|
||||
|
||||
@property
|
||||
def cors_origin_regex(self) -> str | None:
|
||||
regex_parts: list[str] = []
|
||||
for origin in self.api_cors_origins.split(","):
|
||||
normalized = origin.strip()
|
||||
if not normalized:
|
||||
continue
|
||||
if normalized == "*":
|
||||
regex_parts.append(".*")
|
||||
continue
|
||||
if "*" in normalized:
|
||||
wildcard_regex = re.escape(normalized).replace(r"\*", ".*")
|
||||
regex_parts.append(f"^{wildcard_regex}$")
|
||||
|
||||
if self.api_cors_origin_regex:
|
||||
normalized = self.api_cors_origin_regex.strip()
|
||||
if normalized:
|
||||
regex_parts.append(normalized)
|
||||
|
||||
if not regex_parts:
|
||||
return None
|
||||
return "|".join(f"(?:{part})" for part in regex_parts)
|
||||
|
||||
|
||||
@lru_cache
|
||||
|
||||
@@ -25,6 +25,7 @@ app = FastAPI(
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=settings.cors_origins,
|
||||
allow_origin_regex=settings.cors_origin_regex,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
|
||||
@@ -39,6 +39,7 @@ services:
|
||||
API_HOST: ${API_HOST:-0.0.0.0}
|
||||
API_PORT: ${API_PORT:-8000}
|
||||
API_CORS_ORIGINS: ${API_CORS_ORIGINS:-http://localhost:3000,http://127.0.0.1:3000}
|
||||
API_CORS_ORIGIN_REGEX: ${API_CORS_ORIGIN_REGEX:-}
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql+psycopg://fquiz:fquiz@db:5432/fquiz}
|
||||
JWT_SECRET_KEY: ${JWT_SECRET_KEY:-change-this-in-production}
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: ${ACCESS_TOKEN_EXPIRE_MINUTES:-15}
|
||||
|
||||
@@ -180,6 +180,27 @@
|
||||
- 验证:
|
||||
- `cd web && npx eslint src/app/admin/layout.tsx` 通过。
|
||||
|
||||
## 追加修复(CORS 跨域配置增强)
|
||||
|
||||
- 触发问题:
|
||||
- 前端调用 API 出现浏览器 CORS 拦截,需要支持更灵活的来源配置。
|
||||
- 处理:
|
||||
- 后端 CORS 配置增强(`api/app/core/config.py` + `api/app/main.py`):
|
||||
- 新增 `API_CORS_ORIGIN_REGEX` 配置项(可选)。
|
||||
- `API_CORS_ORIGINS` 支持 `*` 与通配符域名(如 `https://*.example.com`),内部转换为正则匹配。
|
||||
- `CORSMiddleware` 增加 `allow_origin_regex=settings.cors_origin_regex`。
|
||||
- 部署与环境模板同步:
|
||||
- `.env.example` 新增 `API_CORS_ORIGIN_REGEX=`。
|
||||
- `docker-compose.yml` API 环境变量新增 `API_CORS_ORIGIN_REGEX` 透传。
|
||||
- `.github/workflows/main.yml` 生产 compose 模板与默认 `.env` 模板同步新增该变量。
|
||||
- 文档补充:
|
||||
- `README.md` 增加 CORS 配置说明与示例。
|
||||
- 验证:
|
||||
- `python3 -m compileall api/app/core/config.py api/app/main.py` 通过。
|
||||
- `docker compose config` 展开结果包含:
|
||||
- `API_CORS_ORIGINS`
|
||||
- `API_CORS_ORIGIN_REGEX`
|
||||
|
||||
## 追加修复(Web 镜像构建 TypeScript 阻塞)
|
||||
|
||||
- 触发问题:
|
||||
|
||||
Reference in New Issue
Block a user