From 8cf375d17857ed8bd4d8ba2e08c20792c018c76a Mon Sep 17 00:00:00 2001 From: dekun Date: Sat, 18 Jul 2026 00:01:51 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20pip=20=E9=95=9C=E5=83=8F=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E6=97=B6=E8=87=AA=E5=8A=A8=E5=9B=9E=E9=80=80=E5=B9=B6?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=BB=A3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EOF Co-authored-by: Cursor --- deploy/install.sh | 4 +-- deploy/proxy.sh | 81 ++++++++++++++++++++++++++++++++++++++++++++++- deploy/update.sh | 3 +- docs/DEPLOY.md | 47 +++++++++++++++++++++++++-- 4 files changed, 129 insertions(+), 6 deletions(-) diff --git a/deploy/install.sh b/deploy/install.sh index bd29d07..aa9a982 100644 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -201,8 +201,8 @@ setup_backend() { fi # shellcheck disable=SC1091 source venv/bin/activate - pip install --upgrade pip --progress-bar on -i "${PIP_MIRROR}" - pip install -r requirements.txt --progress-bar on -i "${PIP_MIRROR}" + pip_install_with_fallback --upgrade pip + pip_install_with_fallback -r requirements.txt deactivate } diff --git a/deploy/proxy.sh b/deploy/proxy.sh index c20e37e..5f90d13 100644 --- a/deploy/proxy.sh +++ b/deploy/proxy.sh @@ -5,6 +5,17 @@ # export https_proxy=http://192.168.8.246:10810 # export HTTP_PROXY="$http_proxy" # export HTTPS_PROXY="$https_proxy" +# +# pip 镜像(可覆盖): +# export PIP_MIRROR=https://mirrors.aliyun.com/pypi/simple + +# 国内镜像优先;代理不可用时仍可走直连镜像。官方源放最后。 +PIP_MIRROR_FALLBACKS=( + "https://pypi.tuna.tsinghua.edu.cn/simple" + "https://mirrors.aliyun.com/pypi/simple" + "https://mirrors.cloud.tencent.com/pypi/simple" + "https://pypi.org/simple" +) setup_deploy_proxy() { local proxy="${HTTP_PROXY:-${http_proxy:-}}" @@ -22,7 +33,17 @@ setup_deploy_proxy() { export HTTPS_PROXY="$https_proxy" export ALL_PROXY="${ALL_PROXY:-$http_proxy}" - if [[ -n "${log_info:-}" ]]; then + # 国内 PyPI 镜像走直连,避免坏代理导致 "from versions: none" + local no_proxy_extra="pypi.tuna.tsinghua.edu.cn,mirrors.aliyun.com,mirrors.cloud.tencent.com,files.pythonhosted.org" + if [[ -z "${NO_PROXY:-${no_proxy:-}}" ]]; then + export NO_PROXY="127.0.0.1,localhost,${no_proxy_extra}" + export no_proxy="${NO_PROXY}" + else + export NO_PROXY="${NO_PROXY:-${no_proxy}},${no_proxy_extra}" + export no_proxy="${NO_PROXY}" + fi + + if declare -F log_info >/dev/null 2>&1; then log_info "使用网络代理: ${http_proxy}" else echo "[INFO] 使用网络代理: ${http_proxy}" @@ -34,3 +55,61 @@ Acquire::http::Proxy "${http_proxy}"; Acquire::https::Proxy "${https_proxy}"; EOF } + +pip_host_from_url() { + # https://host/path -> host + local url="$1" + url="${url#https://}" + url="${url#http://}" + echo "${url%%/*}" +} + +# 用法: pip_install_with_fallback --upgrade pip +# pip_install_with_fallback -r requirements.txt +# 依次尝试 PIP_MIRROR 与备用镜像;失败时给出代理提示。 +pip_install_with_fallback() { + local mirrors=() + local m seen="" + if [[ -n "${PIP_MIRROR:-}" ]]; then + mirrors+=("${PIP_MIRROR}") + fi + for m in "${PIP_MIRROR_FALLBACKS[@]}"; do + mirrors+=("$m") + done + + local mirror host + for mirror in "${mirrors[@]}"; do + case " ${seen} " in + *" ${mirror} "*) continue ;; + esac + seen="${seen} ${mirror}" + + host="$(pip_host_from_url "${mirror}")" + if declare -F log_info >/dev/null 2>&1; then + log_info "pip 安装(镜像: ${mirror})…" + else + echo "[INFO] pip 安装(镜像: ${mirror})…" + fi + + if pip install "$@" --progress-bar on -i "${mirror}" --trusted-host "${host}"; then + return 0 + fi + if declare -F log_warn >/dev/null 2>&1; then + log_warn "镜像不可用: ${mirror},尝试下一个…" + else + echo "[WARN] 镜像不可用: ${mirror},尝试下一个…" + fi + done + + if declare -F log_error >/dev/null 2>&1; then + log_error "所有 pip 镜像均失败(常见原因:服务器无法访问外网 / 代理未设置 / 代理拦截 HTTPS)。" + log_error "请先检测网络,再重试安装:" + log_error " curl -I https://pypi.tuna.tsinghua.edu.cn/simple/fastapi/" + log_error " export http_proxy=http://192.168.8.246:10810" + log_error " export https_proxy=\$http_proxy HTTP_PROXY=\$http_proxy HTTPS_PROXY=\$http_proxy" + log_error " # 或换镜像: export PIP_MIRROR=https://mirrors.aliyun.com/pypi/simple" + else + echo "[ERROR] 所有 pip 镜像均失败。请设置代理或更换 PIP_MIRROR 后重试。" >&2 + fi + return 1 +} diff --git a/deploy/update.sh b/deploy/update.sh index 94dbe54..72c8bbc 100644 --- a/deploy/update.sh +++ b/deploy/update.sh @@ -33,8 +33,9 @@ fi log_info "更新主程序依赖…" cd backend +# shellcheck source=/dev/null source venv/bin/activate -pip install -r requirements.txt --progress-bar on -i "${PIP_MIRROR}" +pip_install_with_fallback -r requirements.txt deactivate cd "${INSTALL_DIR}" diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index 9aea392..07cf016 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -295,7 +295,50 @@ sudo bash deploy/update.sh --- -## 10. 更新后无法访问(连接被拒绝) +## 10. pip 安装失败(No matching distribution / from versions: none) + +若 `install.sh` / `update.sh` 在安装 Python 依赖时报: + +```text +ERROR: Could not find a version that satisfies the requirement fastapi==0.115.6 (from versions: none) +ERROR: No matching distribution found for fastapi==0.115.6 +``` + +说明 **pip 根本拉不到 PyPI 索引**(网络/代理问题),不是版本号写错。 + +在服务器上排查: + +```bash +curl -I https://pypi.tuna.tsinghua.edu.cn/simple/fastapi/ +curl -I https://mirrors.aliyun.com/pypi/simple/fastapi/ +``` + +处理方式(任选其一后重新安装): + +```bash +# 方式 A:走代理后再装(代理地址按实际修改) +export http_proxy=http://192.168.8.246:10810 +export https_proxy=http://192.168.8.246:10810 +export HTTP_PROXY="$http_proxy" +export HTTPS_PROXY="$https_proxy" +cd /opt/secondary-school-grade-archive +sudo -E bash deploy/install.sh + +# 方式 B:换国内镜像 +export PIP_MIRROR=https://mirrors.aliyun.com/pypi/simple +cd /opt/secondary-school-grade-archive/backend +source venv/bin/activate +pip install -r requirements.txt -i "$PIP_MIRROR" --trusted-host mirrors.aliyun.com +deactivate +# 依赖装好后继续跑完安装(或再执行 install.sh) +sudo -E bash /opt/secondary-school-grade-archive/deploy/install.sh +``` + +当前脚本会自动尝试多个镜像;仍失败时请先保证服务器能访问上述 URL。 + +--- + +## 11. 更新后无法访问(连接被拒绝) 若浏览器提示 **ERR_CONNECTION_REFUSED**,通常是 `update.sh` 停止了旧 PM2,但 **systemd 服务未成功启动**。 @@ -319,6 +362,6 @@ ss -tlnp | grep 23566 --- -## 11. 技术支持 +## 12. 技术支持 微信 **dekun03** · 手机 **18364911125**