在自定义 New API 镜像里叠加 PR,修好邮箱绑定

1662 字
8 分钟
在自定义 New API 镜像里叠加 PR,修好邮箱绑定

前面写过一篇《给自用 New API 开放用户统计》,做法是在 Docker 构建时拉取官方源码,改三个地方,再编译成自己的镜像。这个方案一直在用,升级也只是修改 .env 里的 NEW_API_REF,没有另外维护一套仓库。

后来又碰到一个问题:New API 开启 Turnstile 后,个人设置里的邮箱无法绑定,已经绑定过的也无法改绑。前端点发送验证码没有结果,后端实际上在等 Turnstile token,但邮箱绑定界面没有把它带过去。

上游已经有人提交了 PR #6347:fix(profile): include Turnstile token for email binding。截至 2026 年 8 月 21 日,这个 PR 仍然是 open 状态,还没有进入官方主分支。我不想为了一个前端修复再维护长期分支,于是直接把它叠加进原来的补丁镜像。

这里说的“合并 PR”,不是把代码合并进官方仓库,而是在 Docker 构建阶段固定执行一次 cherry-pick --no-commit

PR 修了什么#

这个问题的修复范围不大,改了三个前端文件:

  • 邮箱验证码请求必须接收 Turnstile token,并把 turnstile 参数发给 /api/verification
  • 邮箱绑定窗口先完成 Turnstile 校验,再发送验证码;
  • 请求完成后清空 token,重新创建 Turnstile 组件,避免重复使用过期 token;
  • 给这段请求逻辑补了一份回归测试。

它没有修改 Go 后端、数据库、依赖和锁文件。之前用户统计补丁改的是仪表盘路由和 router/api-router.go,两边没有改同一个文件,直接叠加发生冲突的可能性不大。

修改实际参与构建的 Dockerfile#

我的 Compose 覆盖文件仍然指向原来的补丁目录:

services:
new-api:
build:
context: ./newapi-patched
dockerfile: Dockerfile
args:
NEW_API_REF: ${NEW_API_REF}
image: local/newapi-user-stats:latest
pull_policy: build

所以要改的是服务器上的:

/compose/new-api/newapi-patched/Dockerfile

不是随便找一份源码在宿主机里执行 git cherry-pick。宿主机上的临时源码并不参与 Compose 构建,改了也不会进容器。

先备份原文件:

Terminal window
cp /compose/new-api/newapi-patched/Dockerfile \
/compose/new-api/newapi-patched/Dockerfile.bak

然后在 Dockerfile 的 source 阶段加入 PR 地址和固定提交。原来拉取 NEW_API_REF 的部分改成下面这样:

FROM alpine/git:latest AS source
ARG NEW_API_REF=main
ARG PR_REF=refs/pull/6347/head
ARG PR_SHA=89db50a3fab1beaa26bf6238b70225a914b13893
RUN echo "开始获取 new-api 源码..." \
&& git init /src \
&& git -C /src remote add origin https://github.com/QuantumNous/new-api.git \
&& git -C /src fetch --depth=1 origin "${NEW_API_REF}" \
&& git -C /src checkout --detach FETCH_HEAD \
&& echo "基础源码获取完成: $(git -C /src rev-parse HEAD)" \
\
&& echo "开始应用 PR #6347..." \
&& git -C /src fetch --depth=2 origin "${PR_REF}" \
&& test "$(git -C /src rev-parse FETCH_HEAD)" = "${PR_SHA}" \
&& git -C /src cherry-pick --no-commit "${PR_SHA}" \
&& git -C /src diff --check \
&& echo "PR #6347 应用完成: ${PR_SHA}"
WORKDIR /src

后面的用户统计补丁和编译阶段全部保留。执行顺序变成:

  1. .env 里的 NEW_API_REF 拉取官方基础版本;
  2. 检查并应用 PR #6347;
  3. 继续执行原来的用户统计补丁;
  4. 编译前端和 Go 程序,生成最终镜像。

PR_SHA 固定为 89db50a3fab1beaa26bf6238b70225a914b13893,不是为了写得复杂。PR 还没有合并,作者以后可能继续推送提交。如果只拉 refs/pull/6347/head 而不校验 SHA,哪天重新构建时拿到的代码可能已经变了。现在只要 PR 的 head 发生变化,test 就会让构建立刻停止,至少不会悄悄换掉补丁。

不要把 .env 里的 NEW_API_REF 改成 refs/pull/6347/headNEW_API_REF 是当前使用的官方基础版本,PR 只是叠加在它上面的一个修复。直接替换会把两件事混在一起,也可能把基础版本退回到 PR 作者当时使用的提交。

重新构建并替换容器#

进入 Compose 目录,重新构建:

Terminal window
cd /compose/new-api
docker compose \
-f docker-compose.yml \
-f compose.override.yml \
build --no-cache new-api

构建日志里应该依次出现基础源码提交、应用 PR #6347、用户统计补丁和后续编译过程。确认没有报错后,替换容器:

Terminal window
docker compose \
-f docker-compose.yml \
-f compose.override.yml \
up -d --force-recreate new-api

检查容器状态和最近日志:

Terminal window
docker compose \
-f docker-compose.yml \
-f compose.override.yml \
ps
docker logs --tail=100 new-api

两个补丁都要验证#

容器正常运行不代表功能一定正常。我分别检查了原来的用户统计补丁和这次邮箱修复:

  1. 普通用户登录后仍然能看到 /dashboard/users
  2. 已登录普通用户请求 /api/data/users 返回 200,未登录请求仍然被拒绝;
  3. 管理员页面和原有功能正常;
  4. 开启 Turnstile 后,可以绑定新邮箱,也可以改绑已有邮箱;
  5. 浏览器开发者工具里,发送验证码的 /api/verification 请求同时带有 emailturnstile 参数。

最后一项最直接。请求里只有邮箱、没有 turnstile,就说明页面仍然在使用旧前端,应该先检查镜像是否重新构建、Compose 是否真的替换了容器,不要先去折腾数据库。

如果以后发生冲突#

升级 NEW_API_REF 后,如果构建报下面这种错误:

could not apply 89db50a... fix(profile): include Turnstile token for email binding

说明新的官方源码已经和这个 PR 不兼容,可能是上游改了同一段代码,也可能是修复已经用另一种方式进入主分支。此时旧容器还在运行,构建失败不会自动把它替换掉。

不要删除 SHA 检查,也不要强行跳过冲突继续编译。先看上游是否已经正式解决邮箱绑定问题;如果仍然需要手工处理冲突,就该建一个自己维护的 Git 分支了。Dockerfile 里的临时 cherry-pick 适合这种文件不重叠、改动很小的补丁,不适合长期养一串冲突。

这次没有改 Compose、数据库和原来的用户统计补丁,只是在现有源码阶段多应用一个固定提交。原来的升级方式也不变:更新 NEW_API_REF,重新构建。如果 PR 后续合并进上游,再删除 PR_REFPR_SHA 和对应的 fetchcherry-pick 几行即可。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

在自定义 New API 镜像里叠加 PR,修好邮箱绑定
https://blog.qiui.net/posts/2026-08-21-new-api-email-turnstile-pr/
作者
Qiui
发布于
2026-08-21
许可协议
CC BY-NC-SA 4.0

评论区

文章目录