news 2026/9/4 16:03:50

从 TCP 到 JSON:一次 FastAPI + LLM 生产环境 “Unexpected end of JSON input” 的底层剖析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从 TCP 到 JSON:一次 FastAPI + LLM 生产环境 “Unexpected end of JSON input” 的底层剖析

🔥 从 TCP 到 JSON:一次 FastAPI + LLM 生产环境 “Unexpected end of JSON input” 的底层剖析

关键词:TCP 连接断开、HTTP 分块传输、Nginx 超时机制、FastAPI、LLM 长耗时任务、生产环境架构


一、问题现象

线上部署 FastAPI + AsyncOpenAI 接口后,前端报错:

Failed to execute 'json' on 'Response': Unexpected end of JSON input

浏览器控制台:

SyntaxError: Unexpected end of JSON input

但:

  • 后端日志显示 LLM 请求成功
  • HTML 文件已成功生成
  • 本地 curl 测试完全正常

这意味着:

JSON 本身没有问题
服务器代码没有报错
但客户端收到了不完整的响应


二、问题的真正入口:TCP 连接被强制关闭

我们从最底层开始分析。


1️⃣ HTTP 本质上是 TCP 之上的协议

一次请求的完整链路:

Browser ↓ TCP 三次握手 ↓ HTTP 请求发送 ↓ Server 处理 ↓ HTTP 响应返回 ↓ TCP 连接关闭

只要 TCP 连接被中断:

  • HTTP 响应体会被截断
  • 客户端会收到不完整数据

三、线上环境与本地环境的差异

本地结构

Browser ↓ Uvicorn (FastAPI) ↓ LLM

线上结构

Browser ↓ Nginx ↓ Uvicorn ↓ LLM

这里多了一层:

Nginx 反向代理

四、Nginx 的超时机制(关键)

默认 Nginx 配置:

proxy_read_timeout 60s;

含义:

如果后端在 60 秒内没有返回完整响应
Nginx 会主动关闭 TCP 连接


五、长耗时 LLM 调用触发条件

LLM 生成耗时:

≈ 100 秒

而 Nginx 超时:

60 秒

发生的实际网络行为:


时间线(TCP 级别)

t=0 Browser 发起请求 t=1 请求到达 Nginx t=2 Nginx 转发给 FastAPI t=3 FastAPI 调用 LLM t=60 Nginx 等待超时 t=60 Nginx 发送 FIN/RST t=100 FastAPI 准备返回 JSON t=100 连接已断开

六、TCP 层发生了什么?

当 Nginx 超时:

发送 TCP FIN 或 RST 包

这意味着:

  • TCP 连接被关闭
  • FastAPI 仍然在计算
  • Browser 收到半截 HTTP 响应

七、为什么会出现 JSON 解析错误?

假设服务器本来要返回:

{"status":"success","html":"<!DOCTYPE html>..."}

但连接在传输过程中被中断:

浏览器实际收到:

{"status":"success","ht

于是执行:

awaitresponse.json()

解析到一半 → JSON 结构不完整 → 抛出:

Unexpected end of JSON input

八、为什么服务器日志看不出问题?

因为:

  • FastAPI 没报错
  • LLM 调用成功
  • 文件写入成功

错误发生在:

TCP 连接已经被 Nginx 提前关闭

属于:

网络层错误,而不是应用层错误

九、如何验证是 TCP 层问题?

可以使用:

tcpdump-iany port8000

或者:

ss-tnstate established

你会看到:

  • 连接在 60 秒时被关闭
  • 后端仍然在运行

十、HTTP 与 TCP 的分层问题

很多开发者会混淆:

JSON 错误

实际上是:

TCP 连接异常

这属于典型的:

上层协议误报底层错误


十一、为什么不能简单改超时时间?

你可以修改:

proxy_read_timeout 300s;

但会产生问题:

  • 长时间占用 worker
  • 高并发时资源耗尽
  • 连接池阻塞
  • 服务器扩展性差

本质问题仍然存在:

HTTP 请求生命周期过长


十二、正确架构:脱离 HTTP 生命周期

改造为:

提交任务 → 秒回 job_id 后台执行 → 更新状态 前端轮询 → 查询结果

网络层变化:


改造后的 TCP 行为

Browser ↓ POST (50ms) Nginx ↓ FastAPI → create_task ↓ 立即返回 JSON(job_id) TCP 正常关闭

后台任务独立执行:

FastAPI worker ↓ LLM

前端每 1.5 秒发起新请求:

GET /status/{job_id}

每次都是短连接。


十三、架构对比(TCP 视角)

❌ 同步模式

一个 TCP 连接持续 100 秒

✅ 异步模式

多个短 TCP 连接 每个 < 100ms

十四、底层原理总结

当你看到:

Unexpected end of JSON input

请优先怀疑:

  • 代理层超时
  • TCP 被中断
  • 连接被重置
  • 网关断开

而不是:

  • JSON 编码
  • Unicode 问题
  • FastAPI 序列化

十五、深入一点:RST 与 FIN 的区别

  • FIN:正常关闭连接
  • RST:强制重置连接

Nginx 在超时场景下通常发送 RST。

客户端收到 RST:

  • 立即中断读取
  • 抛出异常

十六、工程启示

1️⃣ 生产环境必须理解网络层

开发者往往只关注:

Python 代码是否报错

但生产问题往往发生在:

TCP / 代理层 / 负载均衡层

2️⃣ 长耗时任务必须异步

只要:

任务 > 30 秒

就应该:

脱离 HTTP 生命周期

十七、最终架构图

Browser ↓ POST (短连接) Nginx ↓ FastAPI (create_task) ↓ 后台 Worker ↓ LLM


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 15:59:53

BEV电池SOC估计为何首选前馈深度神经网络(FDNN)

简介&#xff1a;本资源是一套面向计算机、电子信息工程及数学等专业本科生的电池电动汽车&#xff08;BEV&#xff09;电池电荷状态&#xff08;SOC&#xff09;估计实践代码&#xff0c;聚焦于前馈深度神经网络&#xff08;FDNN&#xff09;在MATLAB平台上的完整实现&#xf…

作者头像 李华
网站建设 2026/9/4 15:58:51

YOLOv8实验室安全行为识别系统:可解释、可部署、可闭环

简介&#xff1a;本资源是一套基于YOLOv8的实验室安全行为识别完整实践方案&#xff0c;面向计算机科学、人工智能、自动化等专业的本科生及初学者&#xff0c;解决实验室场景下不规范操作&#xff08;如未穿实验服、未戴护目镜、违规使用明火等&#xff09;的实时检测与可视化…

作者头像 李华
网站建设 2026/9/4 15:58:03

IGBT与SiC三相四桥臂功率桥测试:开关特性与热性能对比分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/4 15:56:17

AI动漫短剧技术全栈指南:从LLM分镜到视频合成的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/4 15:54:02

Java零基础学习路线:从环境配置到项目实战完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华