平台 Mac 本地部署全过程详细总结
从 2026-09-11 到 2026-09-13,历时三天,从零开始把项目在本机跑通。
本文档按时间顺序,记录每一个问题、每一个报错、每一次修改、每一次验证。
📅 阶段一:VS Code IntelliCode 报错(起点)
报错
Sorry, something went wrong activating IntelliCode support for Python.
Please check the "Python" and "VS IntelliCode" output windows for details.
分析
这是 VS Code 的 IntelliCode 扩展与 Python 语言服务器通信失败。后来证明这个报错与项目本身无关,是编辑器插件层面的问题,可以忽略,不影响项目运行。
处理
暂时搁置,转向真正的目标:把项目跑起来。
📅 阶段二:依赖安装(第一次踩 Python 3.13 的坑)
问题 2.1:shapely 构建失败
报错
ERROR: Failed to build 'shapely' when getting requirements to build wheel
AttributeError: module 'pkgutil' has no attribute 'ImpImporter'
根本原因
- Python 3.13 彻底移除了
pkgutil.ImpImporter(3.12 开始弃用,3.13 正式删除) requirements.txt里锁定的shapely==1.8.5.post1是 2022 年的老版本,它的构建脚本还在用这个被删除的接口- 而且 Shapely 1.x 在 Python 3.13 下没有预编译 wheel,pip 只能从源码编译,必然踩坑
修改
把 backend/requirements.txt 第 23 行:
diff
- shapely==1.8.5.post1
+ shapely>=2.0.4
后续验证
最终装上了 shapely 2.1.2(有 Python 3.13 ARM64 的预编译 wheel)。
问题 2.2:zsh: command not found: pip
报错
bash
like@likeMac backend % pip install -r requirements.txt
zsh: command not found: pip
根本原因
- macOS 系统默认没有全局
pip - 即使用
python3 -m venv .venv创建了虚拟环境,不激活就等于没创建 (pip命令不会自动指向.venv)
修改方案
两种方式等价,任选一种:
方式 A:先激活再调用
bash
cd /Users/like/Desktop/like0909/JiangXi-Platform/backend
source .venv/bin/activate
python -m pip install -r requirements.txt
方式 B:直接用 venv 里的 python(不激活)
bash
cd /Users/like/Desktop/like0909/JiangXi-Platform/backend
.venv/bin/python -m pip install -r requirements.txt
最终成功安装的依赖
Flask 2.2.2, Flask-Cors 3.0.10, flask-marshmallow 0.14.0,
Flask-Migrate 3.1.0, Flask-SQLAlchemy 2.5.1, marshmallow 3.18.0,
marshmallow_sqlalchemy 0.28.1, matplotlib 3.11.1, numpy 1.26.4,
opencv-python 4.10.0.84, openpyxl 3.1.5, Pillow 12.3.0,
PyMySQL 1.2.0, python-dotenv 1.2.3, PyYAML 6.0.3,
scikit_image 0.26.0, SQLAlchemy 1.4.46, sqlparse 0.6.0,
tqdm 4.70.0, Werkzeug 2.2.3, rasterio 1.4.4, shapely 2.1.2
📅 阶段三:理解项目结构与启动机制
关键文件阅读
| 文件 | 作用 |
|---|---|
backend/app.py |
后端入口,工厂模式 create_app() |
backend/.flaskenv_template |
环境变量模板(MySQL 配置、SECRET_KEY 等) |
backend/runtime_frontend_env.py |
读 ../config.yaml + 写 ../frontend/.env |
backend/applications/__init__.py |
create_app() 具体实现 |
backend/applications/configs/config.py |
数据库 URI 构建逻辑 _build_database_uri() |
JiangXi-Platform/config.yaml |
端口/主机/百度地图 key 配置 |
JiangXi-Platform/.env.example |
Docker 部署用环境变量模板 |
关键发现
load_runtime_config()读的是JiangXi-Platform/config.yaml,不是.env_build_database_uri()支持 SQLite :只要DB_BACKEND=sqlite+SQLITE_PATH=<绝对路径>db.create_all()自动建表 ,不需要手动跑init_db.sqlconfig.yaml里的debug: false,开发时最好改成trueinit_script(app)会初始化管理员账号 ,读.env里的ADMIN_USERNAME/ADMIN_PASSWORD
config.yaml 内容(原始)
yaml
port:
backend: 5008
frontend: 3000
host:
backend: 0.0.0.0
frontend: 0.0.0.0
baidu_map:
access_key: <ACCESS_KEY>
debug: false
miner:
enabled: true
frontend_port: 4000
backend_port: 8000
📅 阶段四:Docker 方案(并行备选)
问题 4.1:zsh: command not found: docker
根本原因
Mac 上没装 Docker Desktop。
修改
- 从 Docker 官网下载 Apple Silicon 版 Docker Desktop
- 安装并启动,开启 Settings → General → Use Rosetta for x86_64/amd64 emulation
- Settings → Resources → Memory 至少 8GB(建议 12GB+)
- 验证:
docker --version输出Docker version 29.7.2
问题 4.2:input/output error 导入镜像失败
报错
docker: Error response from daemon: apply layer error ...
failed to commit snapshot extract-...
sha256:6f3b6b3b... input/output error
根本原因
磁盘空间严重不足 。df -h 显示:
/dev/disk3s5 451Gi 409Gi 2.4Gi 100% /System/Volumes/Data
只剩 2.4GB,而镜像解压后要 14.5GB。
修改
清理出空间,最终 125GB 可用。具体清理动作包括:
docker system prune -a(释放 14.54GB)- 清废纸篓、Xcode 模拟器缓存、Homebrew 缓存等
问题 4.3:容器启动后 unhealthy
报错
docker inspect -f '{{.State.Health.Status}}' jiangxi-cpu
unhealthy
详细日志
"Status": "running",
"Running": true,
"OOMKilled": false,
"ExitCode": 0,
"Health": {
"Status": "unhealthy",
"FailingStreak": 8,
"Log": [{ "Output": "Health check exceeded timeout (15s)" }]
}
根本原因
这是误报,不是真的挂了:
- 容器
running,前端 HTTP 200 正常响应 - 健康检查探针命令在 Rosetta 模拟下超时(15秒)
- 不影响实际服务
处理
- 忽略
unhealthy标记 - 容器映射端口:
127.0.0.1:4173→ 容器内 4000(miner)127.0.0.1:4174→ 容器内 3000(前端解译)127.0.0.1:5178→ 容器内 5008(后端)
📅 阶段五:本地 venv 后端启动(主战场)
问题 5.1:ModuleNotFoundError: No module named 'distutils'
报错
File ".../flask_marshmallow/__init__.py", line 10, in <module>
from distutils.version import LooseVersion
ModuleNotFoundError: No module named 'distutils'
根本原因
Python 3.13 移除了标准库 distutils ,而 flask-marshmallow==0.14.0(2020 年发布)还在用它。和 shapely 是同一类问题------旧库 + Python 3.13。
修改
bash
pip install "setuptools<81"
setuptools 内置的 _distutils_hack 会"垫"出 distutils 兼容层。最终装上 setuptools 80.10.2。
验证
bash
python -c "from distutils.version import LooseVersion; print('distutils OK')"
# 输出:distutils OK
问题 5.2:Access denied for user 'root'@'localhost'
报错
pymysql.err.OperationalError: (1045, "Access denied for user 'root'@'localhost' (using password: YES)")
根本原因
.flaskenv 不会被 python app.py 自动加载 。.flaskenv 的自动加载只在 Flask CLI(flask run) 场景下生效(依赖 python-dotenv 的钩子)。
所以 DB_BACKEND=sqlite 没生效,_build_database_uri() 走了默认 MySQL,去连本机并不存在的 MySQL 服务。
修改
采用 flask run 而非 python app.py,并创建 .flaskenv:
bash
cat > /Users/like/Desktop/like0909/JiangXi-Platform/backend/.flaskenv << 'EOF'
FLASK_APP=app.py
FLASK_DEBUG=1
FLASK_CONFIG=development
FLASK_RUN_HOST=127.0.0.1
FLASK_RUN_PORT=5008
DB_BACKEND=sqlite
SQLITE_PATH=/Users/like/Desktop/like0909/JiangXi-Platform/backend/runtime_data/jiangxi.sqlite3
SECRET_KEY=dev-secret-key
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin123
EOF
mkdir -p /Users/like/Desktop/like0909/JiangXi-Platform/backend/runtime_data
问题 5.3:ModuleNotFoundError: No module named 'applications'
报错
flask run
Usage: flask run [OPTIONS]
Error: While importing 'backend.app', an ImportError was raised:
File ".../app.py", line 6, in <module>
from applications import create_app
ModuleNotFoundError: No module named 'applications'
根本原因
flask run 从项目根目录导入 ,把 app.py 当成 backend.app,导致 backend 下的 applications 包找不到。
修改
改用 python -m flask run:
bash
cd /Users/like/Desktop/like0909/JiangXi-Platform/backend
source .venv/bin/activate
python -m flask run
python -m 会把当前工作目录(backend/)加入 sys.path ,applications 就能找到。
成功标志
SQLite 模式,跳过 MySQL 初始化脚本
* Serving Flask app 'app.py'
* Debug mode: on
* Running on http://127.0.0.1:5008
* Debugger is active!
* Debugger PIN: 334-250-063
验证
bash
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:5008/
# 输出:200
问题 5.4:ImportError: numpy._core.multiarray failed to import
报错
File ".../cv2/__init__.py", line 153, in bootstrap
native_module = importlib.import_module("cv2")
ImportError: numpy._core.multiarray failed to import
根本原因
OpenCV 4.10.0.84 与 NumPy 1.26.4 在 Python 3.13 下 ABI 冲突。OpenCV 预编译包绑定了特定 NumPy ABI,版本不匹配导致导入失败。
修改
bash
pip install --upgrade "opencv-python<4.12"
升级到 opencv-python 4.11.0.86。
验证
bash
python -c "import cv2, numpy; print(f'OpenCV: {cv2.__version__}, NumPy: {numpy.__version__}')"
# 输出:OpenCV: 4.11.0, NumPy: 1.26.4
之后后端成功启动。
📅 阶段六:前端启动
操作
bash
cd /Users/like/Desktop/like0909/JiangXi-Platform/frontend
npm install # 装了 939 个包,2 分钟
npm run serve
成功标志
DONE Compiled successfully in 15416ms
App running at:
- Local: http://localhost:3000/
警告(可忽略)
[@vue/compiler-sfc] the >>> and /deep/ combinators have been deprecated.
这是 Vue 3 的废弃警告,不影响运行。
📅 阶段七:miner 启动(BFF 架构)
问题 7.1:ECONNREFUSED 127.0.0.1:8000
报错
[vite] http proxy error: /api/auth/session
Error: connect ECONNREFUSED 127.0.0.1:8000
根本原因
miner 是 BFF 三层架构:
Vite 前端(4000) → Express BFF(8000) → Flask 后端(5008)
看 miner/vite.config.js:
js
proxy: {
'/api': {
target: `http://127.0.0.1:${process.env.MINER_BACKEND_PORT || 8000}`,
changeOrigin: true,
},
...
}
只跑了 Vite 前端(npm run dev),BFF 没跑,所以 8000 端口没人监听。
修改
需要另开终端跑 BFF:
bash
cd /Users/like/Desktop/like0909/JiangXi-Platform/miner
node server.js
问题 7.2:BFF 启动崩溃(缺 geopandas / osgeo)
报错
Error: Command failed: python -c "import geopandas ..."
.../348个图斑.shp
Traceback (most recent call last):
File "<string>", line 6, in <module>
import geopandas as gpd
ModuleNotFoundError: No module named 'geopandas'
During handling of the above exception, another exception occurred:
File "<string>", line 8, in <module>
from osgeo import ogr, osr
ModuleNotFoundError: No module named 'osgeo'
根本原因
BFF 启动时要读 docker/standalone/runtime_data/348个图斑.shp,它调用 Python 子进程:
- 先试
import geopandas - 失败则
from osgeo import ogr, osr - 两个都没装,所以崩了
而且 BFF 是调 PATH 里的 python 命令 ,必须保证这个 python 指向装了 geopandas 的 venv。
修改
在已激活 backend venv 的终端里装:
bash
pip install geopandas
最终装上 geopandas 1.1.4, pandas 3.0.5, pyogrio 0.13.0, pyproj 3.8.0。
关键操作要点
必须在同一个已激活 venv 的终端跑 node server.js:
bash
# 确认 (.venv) 前缀存在
which python
# 应输出:/Users/like/Desktop/like0909/JiangXi-Platform/backend/.venv/bin/python
cd /Users/like/Desktop/like0909/JiangXi-Platform/miner
node server.js
成功标志
[Startup] python runner=PATH:python cmd=python preArgs=
[Startup] loaded jiangxi geojson features=348 source=.../348个图斑.shp
...
Server running at http://localhost:8000
Mode: Local File System (No Database)
附带的警告(暂未处理)
File not found: NDVI_2year.xlsx
File not found: NDBI_by_fid_2year_avg.xlsx
File not found: NDWI_by_fid_2year_avg.xlsx
File not found: NDSI_by_fid_2year_avg.xlsx
这些是光谱指数数据文件缺失,不影响登录和基本功能,光谱指数页面会显示"暂无数据"。
📅 阶段八:前端登录失败(关键突破)
问题 8.1:Network Error / 请求打到 Docker 端口
报错
F12 → Network → login 请求:
Request URL: http://172.31.40.129:5178/api/auth/login
Status: (failed) Network Error
根本原因
frontend/.env不存在 (cat报No such file or directory)- 前端 fallback 到默认值 → 打到 Docker 的
5178端口 - Docker 后端的 CORS 只放行
4173/4174,不放行3000,所以被拦截
第一次错误尝试
我让你创建了这样的 .env:
VUE_APP_BACKEND_PORT = 5008
VUE_APP_BACKEND_IP = localhost
但变量名错了! 查看代码发现:
js
// frontend/src/global.vue:4
const BASEURL = buildBackendUrl(process.env.VUE_APP_BACKEND_URL, window.location);
前端只读 VUE_APP_BACKEND_URL ,不读 VUE_APP_BACKEND_PORT 和 VUE_APP_BACKEND_IP。
最终正确的 .env
bash
cat > /Users/like/Desktop/like0909/JiangXi-Platform/frontend/.env << 'EOF'
VUE_APP_BACKEND_URL = http://127.0.0.1:5008
VUE_APP_BAIDU_MAP_ACCESS_KEY =
EOF
附带修改:后端 CORS 放行本地端口
更新 backend/.flaskenv:
bash
cat > /Users/like/Desktop/like0909/JiangXi-Platform/backend/.flaskenv << 'EOF'
FLASK_APP=app.py
FLASK_DEBUG=1
FLASK_CONFIG=development
FLASK_RUN_HOST=127.0.0.1
FLASK_RUN_PORT=5008
DB_BACKEND=sqlite
SQLITE_PATH=/Users/like/Desktop/like0909/JiangXi-Platform/backend/runtime_data/jiangxi.sqlite3
SECRET_KEY=dev-secret-key
ADMIN_USERNAME=admin
ADMIN_PASSWORD=JiangxiReview-2026!
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000,http://localhost:4000,http://127.0.0.1:4000
EOF
附带修改:重置数据库(让新密码生效)
backend/.flaskenv 里的 ADMIN_PASSWORD 只在首次创建管理员账号时生效。改密码后需要删库重建:
bash
rm -f /Users/like/Desktop/like0909/JiangXi-Platform/backend/runtime_data/jiangxi.sqlite3
下次启动后端时,init_script(app) 会用新密码创建 admin 用户。
关键:前端必须重启
VUE_APP_* 是编译时 注入的,改 .env 后必须重启 npm run serve。
问题 8.2:管理员密码不一致
发现
从用户上传的 jx_env_cpu_20260910.env(Docker 环境变量文件)里找到:
ADMIN_USERNAME=admin
ADMIN_PASSWORD=JiangxiReview-2026!
这是项目方设定的正式密码 。之前我们自定的 admin123 虽然能创建成功,但和 Docker 环境不一致,容易混淆。
修改
把 backend/.flaskenv 里的 ADMIN_PASSWORD 改成 JiangxiReview-2026!,并删库重建。
验证
bash
curl -X POST http://127.0.0.1:5008/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"JiangxiReview-2026!"}' \
-w "\nHTTP_CODE: %{http_code}\n"
返回:
json
{
"code": 0,
"data": { "authenticated": true, "username": "admin" },
"msg": "成功",
"success": true
}
HTTP_CODE: 200
后端登录 100% 正常!
问题 8.3:登录成功!
最终 F12 证据
Request URL: http://127.0.0.1:5008/api/auth/login
Status: 200
Response Headers:
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
Set-Cookie: jiangxi_session=eyJfcGV...; HttpOnly; Path=/
Server: Werkzeug/2.2.3 Python/3.13.2
成功标志
- ✅ CORS 放行
localhost:3000 - ✅ 后端返回会话 cookie
jiangxi_session - ✅ Server 头显示
Werkzeug/2.2.3 Python/3.13.2(本地 Flask) - ✅ Network 里有
session请求(登录后前端在检查会话)
📊 最终运行架构与端口表
本地原生(开发用)
| 终端 | 服务 | 命令 | 端口 | 状态 |
|---|---|---|---|---|
| 1 | Flask 后端 | python -m flask run |
5008 | ✅ |
| 2 | 前端解译 | npm run serve |
3000 | ✅ |
| 3 | miner Vite | npm run dev |
4000 | ✅ |
| 4 | miner BFF | node server.js |
8000 | ✅ |
启动顺序 :后端 → miner BFF → 前端 → miner Vite
(BFF 和前端依赖后端先跑;miner Vite 依赖 BFF 先跑)
Docker(完整栈,能推理)
| 服务 | 端口 | 容器内端口 |
|---|---|---|
| 矿端地图 | 4173 | 4000 |
| 解译平台 | 4174 | 3000 |
| 后端 API | 5178 | 5008 |
关键凭据
| 项 | 值 |
|---|---|
| 管理员账号 | admin |
| 管理员密码 | JiangxiReview-2026! |
| SQLite 数据库 | backend/runtime_data/jiangxi.sqlite3 |
| Flask 端口 | 5008 |
| 前端端口 | 3000 |
| miner Vite 端口 | 4000 |
| miner BFF 端口 | 8000 |
🗂️ 所有修改过的文件清单
| 文件 | 修改内容 |
|---|---|
backend/requirements.txt |
shapely==1.8.5.post1 → shapely>=2.0.4 |
backend/.flaskenv |
新建:SQLite 配置 + CORS + 管理员密码 |
backend/runtime_data/ |
新建目录:存 SQLite 数据库 |
frontend/.env |
新建 :VUE_APP_BACKEND_URL = http://127.0.0.1:5008 |
miner/.env(如有) |
可能需改 BFF 指向 5008(待确认) |
| Python venv 额外包 | setuptools<81、opencv-python<4.12(升到 4.11.0.86)、geopandas |
config.yaml |
未改(debug: false 保持原状) |
🐛 报错速查表
| 报错 | 根本原因 | 一行修复 |
|---|---|---|
module 'pkgutil' has no attribute 'ImpImporter' |
Python 3.13 删了 distutils | shapely>=2.0.4 |
No module named 'distutils' |
同上,旧库还在用 | pip install "setuptools<81" |
No module named 'applications' |
用了 flask run |
改用 python -m flask run |
Access denied for user 'root'@'localhost' |
.flaskenv 没加载 |
python -m flask run |
ImportError: numpy._core.multiarray |
OpenCV 与 NumPy ABI 冲突 | pip install --upgrade "opencv-python<4.12" |
ECONNREFUSED 127.0.0.1:8000 |
miner BFF 没跑 | 另开终端 node server.js |
No module named 'geopandas' |
BFF 缺 Python 依赖 | pip install geopandas |
Network Error 前端登录 |
.env 变量名错 |
改成 VUE_APP_BACKEND_URL |
docker: input/output error |
磁盘空间不足 | 清理到 ≥50GB 可用 |
unhealthy 容器 |
健康检查超时误报 | 忽略(服务实际正常) |
🎯 当前状态与后续
已完成 ✅
- 后端本地跑通(5008)
- 前端本地跑通(3000),登录成功
- miner Vite 跑通(4000)
- miner BFF 跑通(8000)
- Docker 完整栈也能跑(4173/4174/5178)
- 登录凭据统一为
admin / JiangxiReview-2026!
待验证 ⏳
- 前端登录后是否自动跳转到
/segmentation - 解译平台页面功能是否正常(地物分类、光谱指数)
- miner 地图页面是否正常显示 348 图斑
- miner BFF 缺失的 4 个 xlsx 文件(NDVI/NDBI/NDWI/NDSI)------需要向项目负责人索取
已知限制 ⚠️
- Mac 上推理跑不了(mmcv CUDA 算子不可用),语义分割推理必须用 Docker
- miner BFF 缺少光谱指数预计算数据
- Docker 容器
unhealthy标记不影响使用
💡 关键经验教训
-
Python 3.13 是老项目杀手 :
distutils被删、pkgutil.ImpImporter被删、很多 2022 年前的库都没适配。遇到ModuleNotFoundError先想是不是 Python 版本太新。 -
.flaskenv只对flask run生效 ,python app.py不读。想用flask run又怕包路径出错,用python -m flask run。 -
VUE_APP_*是编译时注入 :改.env必须重启npm run serve,浏览器还要强制刷新(Cmd+Shift+R)。 -
前端环境变量名要查代码 ,不能凭猜:
grep -rn "VUE_APP" frontend/src/。 -
BFF 架构的启动顺序 :BFF 要先于 Vite 前端启动,否则代理会报
ECONNREFUSED。 -
BFF 借用 backend venv :因为 BFF 用
child_process调python命令,必须保证 PATH 里的python指向装了geopandas的 venv。 -
磁盘空间是隐形杀手:Docker 镜像动辄十几 GB,Mac 数据分区 2.4GB 可用根本不够。
-
Docker
unhealthy未必真挂:Rosetta 模拟下健康检查超时是常态,看日志确认服务实际是否响应。
**至此,本项目的 Mac 本地部署完成
现象
你在浏览器(http://localhost:3000/#/login?redirect=/segmentation)输入账号密码,点击登录,控制台显示登录成功,但页面死活不跳转到 /segmentation,一直卡在登录页。
排查过程(F12 证据链)
我们通过 F12 开发者工具抓到了三个关键证据:
Application -> Cookies:jiangxi_session 的 Domain 是 127.0.0.1。
Network -> Headers:登录后的 session 请求,Request Headers 里根本没有 Cookie。
浏览器地址栏:前端页面地址是 localhost:3000,但请求的后端地址是 127.0.0.1:5008。
根本原因(第一份文档未覆盖的坑)
浏览器同源策略:浏览器严格将 localhost 和 127.0.0.1 视为两个完全不同的站点。
Cookie 的 SameSite 限制:后端下发的 Cookie 是 SameSite=Lax。当你在 localhost 的页面上,发起对 127.0.0.1 的跨站 XHR 请求时,浏览器直接拒绝携带这个 Cookie。
前端路由守卫拦截:前端拿不到会话(Cookie 没带上),调用 /api/auth/session 失败,路由守卫判定未登录,直接把你踢回登录页。
为什么之前 curl 能成功? 因为 curl 是命令行工具,没有浏览器的同源策略和 SameSite 限制,所以文档 8.3 里 curl 测试是 100% 成功的,但浏览器环境不行。
🛠️ 二、做出的新修改(增量文件清单)
基于第一份文档,我们只做了一处致命且关键的修改:
文件 第一份文档中的状态 我们刚刚的修改 修改原因
frontend/.env VUE_APP_BACKEND_URL = http://127.0.0.1:5008 改为 VUE_APP_BACKEND_URL = http://localhost:5008 保持前后端 Host 一致(同为 localhost),消除跨站限制
注意:后端的 backend/.flaskenv 里的 CORS_ALLOWED_ORIGINS 在第一份文档中已经包含了 http://localhost:3000,所以这次不需要改后端,只需要改前端 .env。
修改后的关键操作步骤:
修改 .env:将后端地址从 127.0.0.1 换成 localhost。
必须重启前端:VUE_APP_* 是编译时注入的。在终端 3(前端)按 Ctrl+C,重新执行 npm run serve。
清理旧 Cookie:在浏览器 F12 -> Application -> Cookies 中,删掉挂在 127.0.0.1 下的 jiangxi_session。
强制刷新:Cmd+Shift+R 刷新页面,重新登录。。