作者: 运维/后端开发
环境: 本地网络 → 阿里云北京服务器
场景: 大文件上传接口 /upload
问题: curl 秒传,浏览器 HTTP 上传极慢(页面已加载完成,无并发阻塞)
一、诡异问题现场
最近在做知识库文件上传功能时,碰到一个非常反直觉、排查到崩溃的问题:
-
curl 命令上传同一个文件 :速度跑满,秒传完成
bashcurl -X POST -F "file=@test.zip" http://xxx/upload --progress-bar -
前端页面浏览器上传:速度几十 KB/s,长时间阻塞,几乎传不动
-
关键前提 :页面完全加载完毕,无其他请求、无轮询、无并发连接抢占
-
协议 :纯
HTTP/1.1,未启用 HTTPS
排除了:服务器性能、带宽、接口逻辑、前端并发阻塞、Nginx 配置...
统统不是问题!
二、核心结论(先给答案)
一句话总结为什么 curl 快、浏览器 HTTP 慢:
浏览器 HTTP/1.1 默认开启 Nagle 算法,与服务器 Delayed ACK 形成"传输死锁",弱网/轻微丢包下速度直接锁死;
curl 默认关闭 Nagle 算法,不受影响;
只有 HTTPS + HTTP/2 能强制浏览器解除限制,恢复全速。
三、底层原理:两个"好心算法"凑成的灾难
1. 两个关键 TCP 机制
(1)Nagle 算法(浏览器默认开启)
- 作用:攒数据包,减少网络小包数量,优化带宽利用率
- 规则:未收到 ACK / 数据未凑满 → 禁止发送新数据
(2)Delayed ACK(Linux/服务端默认开启)
- 作用:延迟回复确认包,合并 ACK,降低网络报文
- 规则:收到数据后,最多等 200ms 再回复 ACK
2. 致命冲突:传输"死锁"(弱网必触发)
浏览器 HTTP/1.1 上传流程:
- 浏览器发送一段文件数据
- Nagle 阻塞:必须等 ACK,不能继续发
- 服务器 Delayed ACK:不立刻回复,等 200ms
- 浏览器 ↔ 服务器:互相死等!
- 每传一小段 → 等待 200ms → 速度锁死在 KB/s 级别
这就是浏览器慢到离谱的真正元凶!
四、为什么 curl 完全不受影响?
关键差异:TCP_NODELAY = 关闭 Nagle 算法
curl 在大文件上传时,默认禁用 Nagle:
- 不攒包
- 不等待 ACK
- 有数据直接发送
- TCP 滑动窗口拉满
即使存在轻微延迟、丢包、跨运营商(访问阿里云),依旧满速跑。
五、为什么 HTTPS + HTTP/2 一开就秒好?
强制规则(浏览器标准)
- HTTP/2 只能在 HTTPS 下启用
- HTTP/2 强制关闭 Nagle 算法
- 多路复用 + 二进制分帧,彻底告别停等机制
- 浏览器发送策略 = curl 行为
开启后:浏览器上传速度 = curl 速度
六、终极解决方案(Nginx + 自签名证书,2 分钟搞定)
1. 生成自签名证书(测试/内网可用)
bash
mkdir -p /etc/nginx/cert
cd /etc/nginx/cert
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.pem -days 3650 -nodes
# 一路回车,无需填写任何内容
2. Nginx 完整配置(直接复制)
nginx
# 80 端口强制跳转 HTTPS
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}
# HTTPS + HTTP/2 核心优化配置
server {
listen 443 ssl http2;
server_name _;
# 自签名证书路径
ssl_certificate /etc/nginx/cert/server.pem;
ssl_certificate_key /etc/nginx/cert/server.key;
# 安全协议配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
# 大文件上传必备
client_max_body_size 1024M;
keepalive_timeout 120;
# 反向代理后端服务
location / {
proxy_pass http://127.0.0.1:8080; # 改成你的后端端口
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
3. 重启 Nginx
bash
nginx -t
systemctl restart nginx
七、效果验证
打开浏览器 F12 → Network
查看协议列:Protocol → h2
代表 HTTP/2 开启成功!
此时再上传文件:
✅ 浏览器速度 = curl 速度
✅ 不再阻塞、不再卡顿
✅ 弱网/阿里云环境依旧稳定满速
八、总结(面试/排查必背)
- curl 快:关闭 Nagle 算法,激进发送
- 浏览器 HTTP/1.1 慢:Nagle + Delayed ACK 死锁
- 与并发、排队、前端代码无关
- HTTP 无法使用 HTTP/2,必须 HTTPS
- 唯一根治方案:HTTPS + HTTP/2
九、一句话记住
浏览器 HTTP/1.1 慢,不是 TCP 慢,是算法冲突拖死了传输;
HTTPS + HTTP/2 关闭 Nagle,浏览器立刻和 curl 一样快!