从 1500ms 到 400ms:一次跨域请求的性能优化
date
Mar 6, 2025
slug
cors-max-age
status
Published
tags
Website
Devops
Cloudflare
Tech
summary
跨域请求的预检耗时是一个容易被忽视的性能瓶颈,性能优化不仅要盯着后端,更要关注全链路
type
Post
最近,我开发了一个新的服务,作为后端开发,我习惯性地在发布前 Review 前端的 API 调用。然而,这次 Review 却让我发现了一个令人费解的问题:某关键接口请求耗时在浏览器显示为 1.5s,但检查后端日志后发现,实际的请求耗时只有 400ms 左右。这就像外卖小哥说餐已送达,而用户却苦等半小时——中间消失的1.1秒究竟被谁偷吃了?
问题发现:前端的 1.5s 与后端的 400ms
在 Review 前端代码时,我注意到一个关键 API 的请求耗时异常高,达到了 1.5s。然而,后端日志显示,这个请求的处理时间仅为 400ms。这意味着,超过 70% 的时间并不是后端处理消耗的,而是发生在前端与后端之间的某个环节。
我打开了 Chrome DevTools 的 Network 面板,分析这个请求的生命周期,一个神秘的"Queueing"阶段映入眼帘,它竟然吃掉了800ms!这个平时容易被忽视的字段,此刻成为了破案的关键线索。
浏览器请求耗时分析:Queueing 阶段的“罪魁祸首”
浏览器网络请求的完整生命周期包含:
在 Network 面板中,我发现这个请求的耗时分布如下:
显然,Queueing 阶段的耗时占了整个请求时间的一半。那么,Queueing 阶段到底在做什么?

浏览器的 Queueing 阶段:请求排队的幕后真相
浏览器的 Queueing 阶段表示请求在等待被发送到网络的时间。通常,它发生在以下场景:
- 同域名TCP连接数超过浏览器限制(Chrome默认6个)
- 请求优先级调度(如HTML/CSS优先于图片)
- 等待前序请求释放连接资源
- 跨域预检:对于跨域请求,浏览器会先发送一个
OPTIONS
预检请求,等待服务器响应后再发送实际请求。
但本案的特殊之处在于:跨域预检请求(Preflight) 让Queueing时间雪上加霜!
问题根源:跨域请求的预检耗时
由于我的前端和后端部署在不同的域名下,浏览器在发送实际请求前,会先发送一个
OPTIONS
预检请求,以确认服务器是否允许跨域请求(CORS预检机制)。这个过程包括:- 浏览器发送OPTIONS预检请求(携带
Origin
、Access-Control-Request-Method
等头)
- 服务器返回
Access-Control-*
系列响应头
- 浏览器确认安全后才发送真实请求
在这个过程中,
OPTIONS
请求的往返时间(RTT)会显著增加请求的总耗时。在我的案例中,OPTIONS
请求的耗时约为 750ms,导致整个请求的耗时达到了 1.5s。而问题就出在:每次跨域请求都要重复这个三部曲!更糟的是,如果预检请求遇到Queueing,整个流程耗时直接翻倍。
优化方案:CORS 预检缓存 与 Nginx 代理
方案一:CORS 预检缓存
通过设置
Access-Control-Max-Age
头,浏览器可以缓存 OPTIONS
预检请求的结果,减少重复预检。后端配置示例:
优点:
- 减少重复的
OPTIONS
请求,简单易实现。
方案二:Nginx 代理
通过 Nginx 代理,将前后端域名统一,也就是域名收敛策略, 将API统一到主域名下,避免跨域问题。
配置示例:
优点:
- 完全避免跨域问题,请求路径更简洁。
结案陈词
这次性能优化让我深刻认识到,跨域请求的预检耗时 是一个容易被忽视的性能瓶颈。通过分析浏览器的 Queueing 阶段,我定位到了问题的根源,并通过CORS 预检缓存 成功解决了这个问题。这个案例告诉我们:性能优化不仅要盯着后端,更要关注全链路。
就像赛车调校,引擎再快也怕变速箱拖后腿。下次看到神秘的Queueing时间,不妨先检查下是否在"跨域交学费"!
(本文完)希望这篇文章能为你带来一些启发,也欢迎在评论区分享你的性能优化经验!👇