在 Chrome 开发者工具的 Network 面板中,看到一个 HTTP 请求的状态始终为 pending,这意味着该请求已经被发起但尚未收到服务器的完整响应。这通常表示请求处于 进行中 的状态,但服务器还未返回任何数据,类似于调试模式下加断点时请求被阻止的状态 。Pending 状态覆盖了从 请求发起 到 收到服务器第一个响应字节 的全过程,只有当服务器返回响应头(例如包含状态码 200)后,pending 状态才会结束,请求状态随之改变 。
🔍 Pending 状态的详细分解
一个 HTTP 请求从发起到完成,其生命周期可以细致地划分为几个核心阶段,pending 状态贯穿了其中多个阶段 :
- 发起请求(Request Initiation):当用户操作(如点击按钮)或前端代码逻辑(如
fetch或axios调用)触发 HTTP 请求时,浏览器的 Network 面板会立即将该请求标记为pending。这表明请求已离开浏览器,但远未处理完成。 - DNS 解析(DNS Lookup):浏览器需要将请求的目标域名(例如
api.example.com)解析为服务器的真实 IP 地址(如192.168.1.1)。浏览器会依次查询本地缓存、系统 hosts 文件、路由器 DNS,甚至递归查询至根 DNS 服务器。此阶段的耗时在 Network 面板的 Timing 标签中显示为DNS Lookup,此时请求状态保持pending。 - TCP 三次握手(TCP Handshake):为了建立可靠的传输连接,客户端(浏览器)与服务器需要通过 TCP 三次握手来协商连接:客户端发送 SYN 包,服务器回复 SYN-ACK,客户端再回复 ACK 包。此过程耗时记录为
Initial Connection,连接建立之前,请求依然为pending状态。 - 发送 HTTP 请求(Request Sent):通过已建立的 TCP 连接,浏览器将 HTTP 请求数据(包括请求行、请求头以及可能的请求体)发送至服务器。此过程通常很快,Network 面板中记为
Request Sent。数据仍在传输途中,故状态仍为pending。 - 服务器处理请求(Server Processing):这是非常关键的阶段。服务器接收到请求后,会执行相应的业务逻辑,例如查询数据库、调用其他微服务或进行复杂计算。此阶段的耗时是
TTFB (Time to First Byte)的主要组成部分。在此阶段,浏览器仍在等待服务器的第一个字节响应,因此请求显示为pending。 - 接收响应(Receiving Response):当服务器开始返回响应头(包含状态码,如 200 OK)时,浏览器 Network 面板中该请求的状态会立即从
pending变为200。随后,服务器继续传输响应体(如 JSON 数据),此过程耗时记为Content Download。
⚠️ Pending 状态的常见原因及诊断方法
导致请求长时间处于 pending 状态的原因多种多样,可归纳为以下四大类:
1. 网络层问题
网络问题通常表现为连接建立困难或数据传输延迟高,其影响范围往往是全局性的(同一网络环境下的多个域名请求可能均受影响)。
- DNS 解析故障或延迟:若 DNS 服务器响应慢或域名解析失败,会导致
DNS Lookup阶段耗时过长。您可以通过在终端执行nslookup your-api-domain.com或dig your-api-domain.com来检查解析时间和结果。 - 网络连接问题:不稳定的网络连接、高延迟或丢包会拖慢 TCP 连接建立和数据传输。
- 诊断方法:
- 使用
ping命令测试到目标服务器的连通性和延迟(例如:ping api.example.com)。频繁丢包(丢包率 > 5%)或延迟剧烈波动通常表明网络链路存在质量问题。 - 使用
tracert(Windows)或traceroute(Linux/macOS)命令追踪路由,查看在哪个网络节点出现高延迟或丢包,这有助于定位网络瓶颈 。
- 使用
- 诊断方法:
- 防火墙或代理拦截:中间网络设备(如公司防火墙或代理服务器)可能会丢弃或延迟某些请求,导致其无法到达服务器。
2. 服务器端问题
服务器端问题是导致 pending 的常见原因,其特征通常是仅针对特定域名或接口的请求出现异常。
- 服务器过载或资源耗尽:当服务器 CPU、内存或磁盘 I/O 使用率过高时,其处理新请求的能力会下降,无法及时响应,直接表现为
TTFB异常升高。 - 应用程序处理缓慢:低效的代码逻辑、复杂的数据库查询、未优化的算法或死锁等问题,都会导致服务器处理单个请求的时间过长。
- 服务器连接数已达上限:服务器操作系统或 Web 服务器软件(如 Nginx、Apache)对并发连接数有限制。当连接数达到上限时,新传入的请求会被放入队列等待或直接丢弃。
- 诊断方法:
- 查看浏览器 Timing 指标:在 Chrome DevTools 的 Network 面板中点击有问题的请求,查看
Timing标签。如果Waiting (TTFB)时间极长(例如超过 3 秒),那么问题极有可能出在服务器处理环节 。 - 检查服务器日志:查看服务器的访问日志(如 Nginx 的
access.log)和应用日志,确认请求是否确实到达了服务器以及服务器处理该请求的耗时。 - 监控服务器资源:使用
top、htop、netstat等命令或监控系统(如 Prometheus + Grafana)实时查看服务器的 CPU、内存、磁盘 I/O 和网络连接数。
- 查看浏览器 Timing 指标:在 Chrome DevTools 的 Network 面板中点击有问题的请求,查看
3. 浏览器端问题与限制
浏览器自身的机制和限制也是导致请求 pending 的重要原因。
- 浏览器并发请求数限制:出于性能和安全考虑,浏览器会对同一域名下的并发 HTTP 请求数量进行限制。例如,Chrome 浏览器允许对同一个域名最多同时发起 6 个 HTTP/1.1 连接 。如果短时间内向同一域名发起超过 6 个请求,多出的请求将会被放入队列(
Queueing)中等待,在 Network 面板中就会显示为pending。 - 高频刷新与资源堆积:在前端开发中,若存在高频触发数据刷新的逻辑(例如用户疯狂点击刷新按钮,或使用极短间隔的
setInterval反复请求),会在极短时间内产生大量请求 。这些请求远超浏览器的处理能力,不仅会导致大量请求pending,甚至可能耗尽浏览器资源,导致页面卡死或出现net::ERR_INSUFFICIENT_RESOURCES错误 。 - 未正确中断的请求:使用
fetch或axios等发起的请求,如果没有通过AbortController或CancelToken及时中断,它们会持续占用连接和资源,即使页面已经跳转或组件已卸载 。
4. 其他原因
- HTTPS/SSL 握手问题:建立 HTTPS 连接所需的 SSL/TLS 握手过程会比 HTTP 连接更耗时,如果服务器证书链复杂或需要进行 OCSP 验证,可能会增加连接的延迟 。
- 第三方依赖问题:如果您的接口依赖于其他第三方服务或 API,那么这些服务的不稳定或高延迟也会间接导致您的接口响应变慢,请求处于
pending状态 。
🛠️ 系统性排查与解决方案
面对一个持续 pending 的请求,建议遵循以下排查流程,逐步缩小问题范围:
-
隔离环境,排除干扰:首先尝试在不同的网络环境(例如切换至手机热点)下访问相同的页面。如果问题随之消失,那么根源很可能在于您的原始网络环境。如果问题依旧,则重点排查服务器和应用程序本身。
-
精读浏览器 Timing 数据:这是前端开发者最直接有效的工具。在 DevTools Network 面板的
Timing标签中,关注几个关键阶段的耗时:Queueing:如果此阶段耗时很长,通常表明请求因浏览器并发数限制而在排队等待。解决方案是优化请求逻辑,减少不必要的并发请求,或通过域名分片(Domain Sharding)技术分散请求。Stalled:请求在发送之前等待的时间。可能是由于浏览器正在等待一个可用的 TCP 连接套接字,这同样与并发连接数限制有关。Waiting (TTFB):这是核心指标。如果 TTFB 过长,几乎可以肯定问题出在服务器端。你需要着手调查服务器性能和应用逻辑。Content Download:响应体下载时间。如果此阶段慢,通常是因为响应数据量过大或网络带宽不足。
-
网络层诊断:如前述,使用
ping和traceroute命令检查网络基础链路是否健康。 -
服务器端深度检查:
- 监控资源:使用服务器监控工具确认 CPU、内存、磁盘 I/O 是否饱和。
- 分析日志:检查服务器日志中该请求的处理记录和耗时。如果日志中根本没有该请求的记录,那么请求可能被防火墙或负载均衡器拦截,未能到达应用服务器。
- 压测与剖析:使用
ab、wrk等工具对可疑接口进行压力测试,同时使用profiler工具(如 Java 的 JProfiler、Python 的 cProfile)分析应用代码,找到性能瓶颈。
-
前端代码优化:
- 规避并发限制:减少同一域名下不必要的并发请求。对于非关键请求,可以采用串行方式(使用
async/await让前一个请求完成后再发起下一个)。 - 实现请求中断:为所有异步请求(特别是用在单页应用 SPA 中的请求)实现取消逻辑。使用
AbortController与fetch配合,或在 axios 中使用CancelToken,在组件卸载或页面跳转时主动中断未完成的请求,释放资源。
// 使用 AbortController 中断 fetch 请求 const controller = new AbortController(); const signal = controller.signal; fetch('https://api.example.com/data', { signal }) .then(response => response.json()) .then(data => console.log(data)) .catch(err => { if (err.name === 'AbortError') { console.log('Fetch aborted'); } else { // 处理其他错误 } }); // 在需要的时候中断请求 controller.abort();- 加入防抖与节流:对于由用户操作频繁触发的请求(如搜索框输入、按钮点击),必须使用防抖(Debounce)或节流(Throttle)技术来限制请求频率,这是避免浏览器资源被耗尽的最佳实践 。
// 使用 Lodash 的节流函数 import _ from 'lodash'; const throttledGetData = _.throttle(function(query) { this.getList(query); }, 1000); // 确保 1 秒内最多执行一次 - 规避并发限制:减少同一域名下不必要的并发请求。对于非关键请求,可以采用串行方式(使用
-
SSE 与长连接管理的注意事项:对于 Server-Sent Events (SSE) 这类长连接,管理不当极易导致
pending请求堆积。务必避免使用单例模式管理连接,因为多个组件同时操作同一个连接实例会导致旧连接无法被正确关闭。应为每个连接创建独立的实例,并在组件卸载时明确关闭对应的连接 。
| 问题类型 | 关键特征/排查点 | 更可能的原因 |
|---|---|---|
| 网络问题 | ping 丢包率高,traceroute 有节点延迟高,所有网站 都慢 |
本地网络拥堵、DNS 故障、运营商网络问题 |
| 服务器问题 | 仅该接口 慢,浏览器 Timing 显示 TTFB 极高,服务器监控显示 CPU/RAM 使用率高 |
服务器过载、应用代码性能瓶颈、数据库查询慢 |
| 浏览器问题 | Network 面板看到大量请求 排队(Queueing),同一域名 下请求过多 | 浏览器并发连接数限制、高频触发请求、未中断的废弃请求 |
💡 结论
Chrome 开发者工具中 HTTP 请求的 pending 状态是一个重要的信号,它指示了请求在生命周期中所处的阶段。长时间持续的 pending 状态通常意味着在请求链路的某个环节存在瓶颈或故障。通过系统性地解读浏览器提供的 Timing 数据,结合网络工具和服务器监控进行交叉排查,您能够准确地定位问题是源于网络基础设置、服务器后端处理还是前端代码逻辑。尤其是对于前端开发者而言,养成良好的编程习惯:主动管理请求生命周期、为频繁操作添加节流控制、并时刻留意浏览器的并发限制,这些措施能有效预防大量 pending 请求导致的页面性能下降甚至崩溃,从而为用户提供更流畅稳定的体验。
















