电脑工场
白蓝主题五 · 清爽阅读
首页  > 网络基础

API接口请求超时,到底卡在哪了?

你写好前端页面,调用后端API,页面转圈半天没反应——F12 打开控制台一看,Network 里那个请求标着 net::ERR_CONNECTION_TIMED_OUT504 Gateway Timeout。不是服务器崩了,也不是代码写错了,就是“等不到回信”。这背后,可能藏着好几个容易被忽略的坑。

网络链路太长,中间一卡就断

从你电脑发请求,到目标服务器响应,中间要经过本地路由器、运营商骨干网、CDN节点、云服务商负载均衡器、防火墙……每一段都可能拖慢甚至中断连接。比如公司内网访问某个海外 API,数据包绕了三四个中转站,某段线路抖动或丢包率高,TCP 重传几次失败,客户端就直接放弃,报超时。

服务端处理太慢,自己都忙不过来

常见于未做限流或资源隔离的接口。比如一个查订单详情的接口,内部顺带拉了用户画像、推荐商品、优惠券列表、物流轨迹——7 个子查询串行执行,数据库慢查询没加索引,单次响应耗时 8 秒。而前端默认 timeout 是 5 秒,自然收不到结果。

再比如 PHP-FPM 进程数设成 10,同时来了 15 个请求,后面 5 个就得排队等。排在队尾的请求,光是等 worker 空闲就花了 3 秒,再加业务逻辑 4 秒,妥妥超时。

客户端设置太“心急”

很多开发者习惯性把 timeout 设得很短:axios 默认 0(无限),但有人手动写成 1000 毫秒;fetch 不设 signal 就没超时机制;小程序 wx.request 的 timeout 默认才 6000 毫秒,遇到稍复杂的聚合接口很容易踩线。

示例:

fetch('/api/order', { timeout: 2000 }) // 错误写法:fetch 原生不支持 timeout 选项

正确做法得靠 AbortController:
const controller = new AbortController();
timeoutId = setTimeout(() => controller.abort(), 2000);
fetch('/api/order', { signal: controller.signal })
  .then(r => r.json())
  .catch(err => {
    if (err.name === 'AbortError') console.log('请求超时');
  });

DNS 解析卡住,还没出发就凉了

尤其在移动网络或某些企业代理环境下,DNS 查询可能长达 3~5 秒。如果 DNS 缓存失效,又碰上 DNS 服务器响应慢,请求连 IP 都没拿到,自然超时。可以试试用 nslookup api.example.comdig api.example.com 看解析耗时。

SSL/TLS 握手失败或过慢

HTTPS 请求比 HTTP 多几步:TCP 连接 → TLS 握手(含证书校验、密钥交换)→ 发送 HTTP 请求。若服务端证书链不全、OCSP 响应慢、或客户端不支持服务端启用的 TLS 版本(比如只支持 TLS 1.2,但服务端强制 1.3),握手阶段就会卡住甚至失败。

别光盯着代码,先看真实路径

遇到超时,别急着改代码。打开命令行,分步测:

ping api.example.com              # 看通不通、延迟高不高
curl -v https://api.example.com # 看 DNS、TCP、TLS 各阶段耗时
curl -m 3 -I https://api.example.com # 强制 3 秒超时,观察是否稳定失败

能定位到哪一步挂掉,修起来才不盲目。