最近在开发一个代码审查工具时,遇到了一个有意思的问题。本地测试一切正常,但调用线上API时却一直 失败。整个排查过程挺有意思的,记录下来分享给大家。
背景
我们团队开发了一个内部的代码审查系统,前端使用React,后端是Node.js + Koa框架。最近在开发一个CLI工具,需要调用后端API上传代码审查报告。
问题现象
本地开发时,CLI工具调用本地服务一切正常: POST http://localhost:34789/document/createCodeReviewDocument 返回 200 OK
但调用线上服务时,却返回了405错误: POST gw.example.com/document/cr... 返回 405 Method Not Allowed
排查过程
第一阶段:路由问题
首先怀疑是路由配置问题。查看后端代码发现,我们的路由分为公有路由和私有路由:
- 公有路由:/public/* (登录等接口)
- 私有路由:直接挂载,无前缀
但通过浏览器开发者工具发现,线上其他接口都是通过 /api/* 访问的。原来是Nginx做了路由转发:
bash
location /api/ {
proxy_pass http://backend/;
}
第一个坑:线上需要加 /api 前缀,而本地不需要。
第二阶段:认证问题
修复URL后,405错误解决了,但又出现了新问题:
bash
{
"success": false,
"errorCode": 40403,
"errorMsg": "{\"code\":9999}"
}
9999是我们系统的默认错误码,说明出现了未知异常。为了定位问题,我临时修改了错误处理代码,让它 返回详细错误信息:
bash
} catch (error) {
// 临时添加详细错误信息
throw new CodedError(error.message || '系统错误')
}
第三阶段:数据库连接?
重新部署后,发现本地连接生产环境会报数据库连接超时。这很正常,因为阿里云RDS有IP白名单限制。
但奇怪的是,其他接口(如 getProjectList)能正常返回数据,说明线上服务是能访问数据库的。那问题出在哪里?
第四阶段:真相大白
最后实在没办法,只能登录服务器查看日志。PM2的日志暴露了真正的问题:
bash
RequestTimeTooSkewedError: The difference between the request time and the current time is too large.
原来是服务器时间不同步!
阿里云OSS有个安全机制:请求时间与服务器时间差不能超过15分钟。我们的服务器时间慢了20多分钟。
解决方案
解决方法很简单,同步服务器时间:
同步时间
bash
ntpdate ntp.aliyun.com
设置定时同步
bash
echo "*/30 * * * * /usr/sbin/ntpdate ntp.aliyun.com" >> /var/spool/cron/root
重启服务
bash
pm2 restart all
经验总结
- 不同环境的差异要重视 - 本地和线上的路由配置可能不同(Nginx转发规则) - 注意时区和时间同步问题
- 错误处理很重要 - 默认的错误码(如9999)掩盖了真实问题 - 开发环境可以返回详细错误,生产环境要注意信息安全
- 日志是排查问题的关键 - 不要只看API返回,要看服务端日志 - PM2、系统日志都可能包含关键信息
- OSS等云服务的特殊要求 - 时间同步是基础但容易被忽略 - 签名机制对时间很敏感
- 排查思路 - 从表象到本质,层层深入 - 对比正常接口和异常接口的差异 - 必要时登录服务器查看详细日志
这次问题虽然最后解决很简单,但排查过程还是学到不少东西。特别是时间同步这种基础设施问题,平时 不注意,出问题的时候还真不容易想到。
PS: 感谢团队小伙伴们的支持,特别是运维同学提供的服务器权限。