fix: 前端同源代理 /api → 后端(任意 IP 访问不再 NetworkError)+ SQLite 写锁等待

- 根因①:页面硬编码 http://127.0.0.1:8000/api,从 192.168.1.160:3000 访问时浏览器请求自身/跨域失败
- 根因②(500):全市场数据同步(长写事务)持有 SQLite 锁导致读接口 database is locked
- 前端:next.config.ts rewrites /api/* → http://127.0.0.1:8000/api(BACKEND_API_URL 可覆盖);
  lib/api.ts 默认相对 /api 同源(NEXT_PUBLIC_API_BASE 保留为直连覆盖项);.env.local.example 说明两种方式
- 后端:CORS 开发期 allow_origins=["*"](无凭据,上线前收紧);SQLite engine busy_timeout=30s
- USAGE FAQ 同步;验证:192.168.1.160:3000/api/health 与 /api/factors 经代理 200,CORS 头 access-control-allow-origin: *
This commit is contained in:
Simon
2026-09-06 19:00:49 +08:00
parent fc12ba89ad
commit b78852f01b
6 changed files with 53 additions and 10 deletions
+6 -3
View File
@@ -1,7 +1,7 @@
# qlib-platform 使用说明
> 适用代码版本:M1–M5 全部完成,含 QlibEngine v1(Qlib 数据管线)与 Parquet 导出
> (HEAD ≈ `bbb5c1e`);若文档与代码不一致,以代码与
> (HEAD ≈ `fc12ba8`);若文档与代码不一致,以代码与
> [ARCHITECTURE.md](./ARCHITECTURE.md) / [ROADMAP.md](./ROADMAP.md) 为准。
>
> 本文覆盖:安装配置、数据同步、启动前后端、研究 API、研究引擎与 Qlib 接入、
@@ -291,8 +291,11 @@ pnpm run build
中向 `ResearchService` 注入 `QlibEngine()` 启用 QlibDataset 数据管线(见 §6.1)。
- **Parquet 导出文件在哪、怎么读**:`data/parquet/stock_daily/<year>.parquet`;
`pd.read_parquet(...)` 直接读取(pyarrow 已随依赖安装)。
- **前端连不上后端**:确认后端运行在 8000、`frontend/web/.env.local` 的
`NEXT_PUBLIC_API_BASE` 正确、CORS 白名单含 `localhost:3000 / 127.0.0.1:3000`。
- **前端连不上后端 / NetworkError**:前端默认经 Next **同源代理**访问 `/api/*`
(next.config.ts rewrites → `127.0.0.1:8000`,可用 `BACKEND_API_URL` 覆盖),
任意 IP 访问 `:3000` 都不需要 CORS 或硬编码后端地址;后端 CORS 开发期为 `*`。
若 API 返回 500 且日志出现 `database is locked`,多半是正在跑全市场数据同步
(长写事务),同步结束后自动恢复(引擎已加 busy_timeout 等待)。
- **数据库被改动想重置**:删除 `data/quant.db` 后 `uv run alembic upgrade head` 重建
表结构(行情需重新同步)。
- **想切换 MySQL**:`.env` 设 `DATABASE_URL=mysql+pymysql://user:pass@host/db`,