现象

博客的评论区一直在转圈,一直以为是「没人评论所以空的」。

直到有一天为了查别的问题去调评论接口,发现请求根本没回来:

curl -X POST https://xxx.vercel.app/ → 超时

第一步:先看 DNS,别急着改代码

nslookup xxx.vercel.app

结果:

Addresses:  2a03:2880:f12c:183:face:b00c:0:25de
31.13.85.2

face:b00c 是 Facebook 的 IPv6 特征段,31.13.x 也是 Facebook 的地址块。再查一个对照组:

nslookup vercel.com        → 64.239.123.1   ✅ 正常
nslookup test.vercel.app → 208.43.170.231 + face:b00c ❌ 同样被劫持

结论:***.vercel.app 整段被 DNS 污染**,解析结果全被指到 Facebook 的 IP 上,所以永远连不上。Vercel 本身没问题,vercel.com 是好的。

这也解释了为什么有些人抱怨「Vercel 上的服务国内打不开」——不是平台的问题,是域名被挡住了。

第二步:自定义域名能用,但有版本坑

我早先给评论服务绑过一个自定义域(twikoo.xxx.com,CNAME 到 Vercel 的 DNS),这个域名没被污染,200 正常响应。

但调接口返回:

{"code":1001,"message":"请更新 Twikoo 云函数至最新版本"}

按字面意思,应该去升级后端。于是我把后端镜像从头到尾换了几个版本——升到最新还是 1001。

回头看源码才发现,这句文案是误导的:

// @twikoojs/common
EVENT_NOT_EXIST: 1001,

1001 的真实含义是「事件不存在」。

这就对上了:前端加载的是 1.6.x,发的是 GET_COMMENTS 事件;后端早就是 2.x,事件名变了,直接不认。而提示文案还留在旧版本那句话上。

验证方法:换成不涉及事件名的接口试试:

GET_CONFIG            → 正常返回配置
GET_RECENT_COMMENTS → 正常返回评论数据
GET_COMMENTS → 1001

配置能读、数据能读,只有那一个事件不通——根本不是版本太旧,是前后端事件名对不上。

第三步:干脆搬回自己机器

既然域名被污染、版本又纠缠,索性不再依赖 Vercel。自己的服务器上跑一个容器就行:

docker run -d --name twikoo \
--restart unless-stopped \
--env-file /root/twikoo.env \
-p 127.0.0.1:8082:8080 \
-v /mydata/twikoo/data:/app/data \
imaegoo/twikoo:latest

几个要点:

  • **只监听 127.0.0.1**,公网访问一律走 nginx 反代
  • 数据库连接串放在 --env-file 里,文件权限 600,不要写在命令行(会进 shell history)
  • 数据库还是用原来的 MongoDB Atlas,历史评论不用迁,连上就能读

/root/twikoo.env:

MONGODB_URI=mongodb+srv://用户:密码@集群/?retryWrites=true&w=majority
TWIKOO_THROTTLE=1000

第四步:nginx 反代到一个路径

不想再折腾子域名和证书,直接挂在主域名的路径下:

location ^~ /api/twikoo {
rewrite ^/api/twikoo/?(.*)$ /$1 break;
proxy_pass http://127.0.0.1:8082;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

rewrite ... break 那行是关键:容器的接口在根路径 / 上,请求进来是 /api/twikoo,必须把前缀削掉再转发,否则容器收到 /api/twikoo 会 404。

博客配置改成:

twikoo:
envId: https://你的域名/api/twikoo

好处是:不用动 DNS、不用单独申请证书,主域名有什么配置它就用什么。

第五步:前端也得是 2.x

后端换好了,前端还停在 1.6.x,照样不通。但直接改版本号会撞墙:

https://cdn.staticfile.org/twikoo/2.0.17/twikoo.all.min.js  → 404
https://cdn.staticfile.org/twikoo/1.6.31/twikoo.all.min.js → 200

国内 CDN 只同步到 1.6.31,jsdelivr 这边又连不上。绕开的办法是从国内 npm 镜像把包下下来,放到自己站点里:

curl -o source/js/twikoo.all.min.js \
"https://registry.npmmirror.com/twikoo/2.0.17/files/dist/twikoo.all.min.js"

然后在主题配置里覆盖这个脚本的地址(Butterfly 支持逐个插件指定 URL):

CDN:
option:
twikoo: /js/twikoo.all.min.js

顺带的好处:评论系统不再依赖任何外部 CDN,外部 CDN 出问题、域名被墙,跟我没关系了。

结果

项目 之前 现在
评论接口 *.vercel.app,国内不通 自己的域名/api/twikoo
前端脚本 第三方 CDN 1.6.x 本站托管 2.0.x
数据 Atlas Atlas(不变,直接沿用)
部署平台 Vercel 自己的 Docker

历史评论一条没丢——数据一直在数据库里,之前只是「接口调不通」,不是「数据没了」。

复盘

这次真正花时间的不是部署,是被错误提示带偏。「请更新云函数」这句话让我在后端版本上兜了好几圈,而真实原因(事件名变了)藏在源码的一个常量定义里。

遇到报错,尤其是第三方封装过的报错,先去查错误码的真实定义,别信文案。