shiro无法连接api服务
问题追踪
访问网站显示禁止访问或者API服务出现问题
网站报错pm2 logs shiro --lines 50
发现报错ETIMEDOUT
日志报错
使用curl
指令可拿到200
响应
fetch
却抛 AggregateError [ETIMEDOUT],
堆栈停在 internalConnectMultiple
问题分析
Node 20+ 对 “Happy Eyeballs” 实现缺陷 引发的典型现象:
Node 为了在 IPv4/IPv6 之间“自动选路”,先尝试第一条记录,仅给 250 ms ⏱️;若未握手成功就强制取消,再去连另一族协议,结果两边都可能超时
Curl 默认不用这套机制,所以一直成功。
修复方案
检查node版本
node -v # 若 ≥ 20 则命中此 Bug
一次性验证
NODE_OPTIONS="--network-family-autoselection-attempt-timeout=5000" node -e "await fetch('https://server.gufei.life/api/v2/aggregate?theme=shiro').then(r=>console.log(r.status))"
# 如果打印 200,说明问题消除
输出 200
,说明 Happy Eyeballs 的 250 ms 默认握手窗口 正是罪魁祸首;把窗口拉大到 5 s 后便一切正常。
修改ecosystem.config.js文件
/**
* /root/shiro/ecosystem.config.js
*/
module.exports = {
apps: [
{
name: 'shiro',
script: 'server.js',
autorestart: true,
watch: false,
max_memory_restart: '500M',
/* 方式 A——通过环境变量注入给 Node */
env: {
PORT: 2323,
NODE_ENV: 'production',
NEXT_SHARP_PATH: process.env.NEXT_SHARP_PATH,
NODE_OPTIONS:
'--network-family-autoselection-attempt-timeout=5000 --dns-result-order=ipv4first',
},
/* 方式 B——直接让 PM2 把参数作为 node_args 传递 */
node_args:
'--network-family-autoselection-attempt-timeout=5000 --dns-result-order=ipv4first',
log_date_format: 'YYYY-MM-DD HH:mm:ss',
},
],
};
重新运行服务使配置生效
pm2 delete shiro # 清掉旧进程(日志文件仍在)
cd /root/shiro
pm2 start /root/shiro/ecosystem.config.js
观察是否修复完成
pm2 logs shiro --lines 50
只要日志里再也没有
AggregateError [ETIMEDOUT]
/ TypeError: fetch failed
就说明彻底生效了。