Nginx从1.25版本开始正式支持HTTP/3,很多团队已经将其用于反向代理回源场景。在使用过程中,错误日志里偶尔会出现“StopSending frame received”的记录,这行信息背后对应的是QUIC协议中的停止发送帧。HTTP/3基于QUIC传输,每个请求对应一个独立的双向流,当某一方不再需要接收数据时,就会发送StopSending帧通知对方停止发送。Nginx作为客户端回源时收到该帧,说明上游服务器希望立即终止这个流上的数据发送。理解这个现象需要先弄清楚QUIC流的状态管理和HTTP/3的取消语义。

在QUIC中,StopSending帧和RESET_STREAM帧通常成对出现:一方发送StopSending表示“我不想再接收数据”,另一方回应RESET_STREAM表示“我已停止发送”。对于HTTP/3来说,StopSending帧通常用于取消一个正在进行的请求,例如客户端导航到新页面或下载被用户中断。但在Nginx回源的场景中,上游服务器才是发送StopSending的一方,所以问题更多出在上游服务或中间网络。
日志中StopSending帧的详细解读
先看一段典型的Nginx错误日志输出:
2025/04/12 10:22:31 [error] 12345#12345: *67890 upstream sent StopSending frame with error code 0x0100, stream id 0x04 while sending request to upstream, client: 192.168.1.100, server: ipipp.com, request: "GET /api/data HTTP/3", upstream: "https://10.0.0.5:443"
这段日志包含几个关键信息:错误码0x0100对应HTTP/3的H3_REQUEST_CANCELLED,stream id 0x04表明这是一个客户端发起的双向流。请求方法为GET,说明Nginx正在向上游转发请求体或等待响应时,收到了StopSending。HTTP/3中不同的错误码有明确的含义,0x0100表示请求被取消,0x010C表示服务器拒绝处理,0x010D表示请求不完整。如果错误码是0x0100,大概率是用户操作,比如客户端断开连接或浏览器的取消行为通过某种方式传递到了上游。
另一种情况是错误码为0x0000(NO_ERROR),这并不代表没有错误,而是意味着发送方想正常终止该流的接收方向。配合stream id可以判断是请求流还是推送流。如果stream id为0x00~0x03,那是QUIC的保留流;如果是偶数,则是客户端发起的流;奇数则为服务器发起的流。回源时,Nginx作为客户端发起的流一般是偶数,所以stream id为0x04是第一个请求流,这很常见。理解这些细节能帮助我们在海量日志中快速过滤出真正需要关注的记录。
触发StopSending帧的常见原因
上游服务器发送StopSending帧的原因可以归纳为几类。第一类是客户端提前断开连接。Nginx在接收到客户端断开事件后,会尝试取消对应的上游请求,如果上游已经进入发送数据阶段,Nginx可能会向上游发送RESET_STREAM,而上游如果同时也在接收方向遇到问题,可能会回发StopSending。不过这种情况通常Nginx日志会同时记录“client prematurely closed connection”,需要对比时间线。
第二类是上游服务器自身的逻辑。例如上游使用Go的net/http包或基于quic-go的HTTP/3实现,当处理函数调用了请求上下文的取消操作,或者上游认为请求体读取超时,就会向对端发送StopSending。另外,如果上游服务器检测到请求头过大、流控窗口耗尽或应用层主动调用http.Request.Body.Close,也会触发。某些反向代理或网关程序在转发时会因为内部错误主动终止流,这些错误往往会记录在上游自己的日志中。
第三类是QUIC连接层面的问题。比如网络路径发生变化,导致连接迁移失败;或者Nginx和上游的QUIC加密套件、拥塞控制算法不兼容,使得某个流的传输卡死,触发上层超时。还有一些Nginx版本在回源HTTP/3时对动态表更新处理不完善,当上游发送头部更新时Nginx未能正确响应,上游误认为对端异常而发送StopSending。这类问题通常与具体版本有关,可以通过升级Nginx到最新稳定版解决。
实战排查思路与配置调整
排查的第一步是确认日志中StopSending出现的位置和频率。如果只是偶尔出现,且伴随客户端断开,可以视为正常取消,无需处理。如果大量出现且业务受影响,就需要抓包分析。可以使用qlog或wireshark的QUIC支持功能,打开捕获文件后过滤“h3.stop_sending”帧,查看stream id和error code。结合Nginx的access log对比请求的最终状态,能判断是上游主动取消还是中间设备干扰。
Nginx侧有几个配置可能影响回源HTTP/3的行为。首先是proxy_http_version 3.0;,这行指令必须在location或server块中显式启用,同时需要配置proxy_ssl_protocols TLSv1.3;。如果使用proxy_quic相关指令,需要确认Nginx编译时包含了HTTP/3模块。其次,proxy_read_timeout和proxy_send_timeout的值设置过短,可能导致Nginx在等待上游响应时主动关闭流,而上游尚未完成发送,从而触发StopSending。适当延长这两个超时时间可以减少误报。另外,proxy_request_buffering如果设为off,Nginx会将客户端请求体边接收边转发给上游,此时客户端断开会更容易导致上游产生StopSending,开启缓冲可以缓解。
如果排查后发现是上游服务器的问题,可以检查上游的HTTP/3实现。例如Caddy、Envoy或自研服务,确保它们的最新版本修复了流控相关的bug。对于写死的错误码,可以添加上游日志输出,观察触发StopSending时的请求上下文。有些上游框架在请求处理panic时会终止流,这时错误码通常是H3_INTERNAL_ERROR(0x0102),需要修改代码避免panic。此外,调整QUIC的连接空闲超时和流控窗口大小,有时能减少因网络抖动引起的流取消。
最后,如果Nginx版本较老,建议升级到1.27或更高版本,因为HTTP/3回源功能在早期版本中还存在一些已知问题,比如对某些帧类型的处理不完整。可以通过nginx -V查看编译参数,确认是否包含--with-http_v3_module。升级后观察日志,必要时结合quic_stream_buffer_size等指令微调流控参数。
StopSending帧不是洪水猛兽,它只是QUIC协议中正常的流控制信号。只要理解了它的触发场景,就能快速定位是网络问题、配置问题还是应用逻辑问题,避免在日志噪音中浪费精力。
Nginx日志HTTP/3StopSending帧修改时间:2026-10-02 02:22:55