Loading... 最近在部署 ChronoFrame 的过程中遇到了一个比较奇怪的问题: > **上传照片时提示 `Preprocessing timeout`,但是部分照片又能够正常上传。**  一开始我以为是 ChronoFrame 自己的图片预处理超时,后来通过查看 Docker 日志、分析 Worker 机制以及检查 OpenList 的反向代理配置,最终发现真正的问题出在: > **Nginx 反向代理的超时时间过短,导致 ChronoFrame → OpenList 的上传请求超时,并返回 504 Gateway Time-out。** 最终只需要调整 Nginx 的上传相关配置,问题就解决了。 本文记录一下完整的排查过程。 --- ## 一、我的存储架构 我的 ChronoFrame 使用 Docker 部署,照片并不是存储在 ChronoFrame 容器本地,而是通过 OpenList 存储到 115 网盘。 整体架构如下: ```text 浏览器 │ ▼ ChronoFrame │ │ HTTPS ▼ open.fivk.cn │ │ Nginx 反向代理 ▼ OpenList │ ▼ 115 网盘 ``` ChronoFrame 中的 OpenList 配置大致如下: ```env NUXT_STORAGE_PROVIDER=openlist NUXT_PROVIDER_OPENLIST_BASE_URL=https://open.fivk.cn NUXT_PROVIDER_OPENLIST_ROOT_PATH=/手机相册/chronoframe NUXT_PROVIDER_OPENLIST_TOKEN=****** ``` OpenList 本身运行在服务器的: ```text 127.0.0.1:5244 ``` 宝塔负责 `open.fivk.cn` 的 HTTPS 和反向代理。 --- # 二、问题:上传照片提示 `Preprocessing timeout` 在 ChronoFrame 上传照片时,经常出现: ```text Preprocessing timeout ``` 有时候上传失败,有时候又能成功。 一开始我的第一反应是: > ChronoFrame 是不是处理图片太慢了? 因为错误信息本身就是: ```text Preprocessing timeout ``` 看起来很像: ```text 上传照片 ↓ ChronoFrame 图片预处理 ↓ 处理时间超过限制 ↓ Preprocessing timeout ``` 所以最开始我把注意力放在了 ChronoFrame 的图片处理和 Worker 上。 --- # 三、查看 ChronoFrame 日志 首先查看 Docker 日志: ```bash docker logs -f chronoframe ``` 发现了几个非常关键的错误。 首先是: ```text [cframe/queue:worker-1] ERROR Task 159 processing failed Preprocessing failed ``` 随后: ```text [cframe/queue:worker-1] ERROR Task 159 failed permanently after 3 attempts: Preprocessing failed ``` 看起来确实像是 ChronoFrame 处理失败。 但是继续往前看,又发现了一个更加关键的信息: ```text [cframe/storage] ERROR OpenList upload failed { status: 504, body: '<html> <head><title>504 Gateway Time-out</title></head> <body> <center><h1>504 Gateway Time-out</h1></center> <hr><center>nginx</center> </body> </html>' } ``` 随后 ChronoFrame 又报: ```text [cframe/main] ERROR Storage provider create error: OpenList upload failed: 504 ``` 这就开始有意思了。 **ChronoFrame 表面上告诉我的是 `Preprocessing failed`,但底层实际上出现了 OpenList 504。** --- # 四、而且并不是所有照片都失败 更加奇怪的是,日志里面同时存在成功上传: ```text [cframe/storage] ✔ Uploaded object: /手机相册/chronoframe/51921.jpg [cframe/storage] ✔ Uploaded object: /手机相册/chronoframe/51910.jpg [cframe/storage] ✔ Uploaded object: /手机相册/chronoframe/51911.jpg ``` 也就是说: ```text 同一个 ChronoFrame │ ├── 图片 A → 上传成功 ├── 图片 B → 上传成功 ├── 图片 C → 504 ├── 图片 D → 504 └── 图片 E → 失败 ``` 这基本可以排除: - OpenList URL 完全错误 - Token 完全错误 - OpenList 路径完全错误 - ChronoFrame 无法连接 OpenList 因为如果这些配置错了,应该不会出现大量成功上传。 更像是: > **请求偶尔能够完成,但部分上传请求等待时间过长,最终被某一层超时关闭。** --- # 五、ChronoFrame 默认有 5 个 Worker 继续检查 ChronoFrame 源码,发现 WorkerPool 的配置: ```ts const workerPool = new WorkerPool( { workerCount: 5, intervalMs: 1500, intervalOffset: 300, enableLoadBalancing: true, statsReportInterval: 60000 * 10, }, _logger, ) ``` 也就是说 ChronoFrame 默认启动: ```text Worker 1 Worker 2 Worker 3 Worker 4 Worker 5 ``` 同时日志也验证了这一点: ```text Total Workers: 5 ``` 当批量上传照片时,可能会有多个任务同时进行。 例如: ```text Worker 1 ──→ 上传照片 A Worker 2 ──→ 上传照片 B Worker 3 ──→ 上传照片 C Worker 4 ──→ 上传照片 D Worker 5 ──→ 上传照片 E ``` 因此当 OpenList 后面的 115 上传比较慢时,并发上传可能进一步增加压力。 不过这里需要注意: > **5 个 Worker 本身并不是最终确认的根因。** 因为日志已经出现了非常明确的: ```text 504 Gateway Time-out nginx ``` 所以继续往 Nginx 方向排查。 --- # 六、先测试 OpenList 的网络连接 在 ChronoFrame 所在服务器上执行: ```bash curl -I https://open.fivk.cn ``` 返回: ```text HTTP/2 405 server: nginx ``` 一开始看到 `405` 可能会以为有问题。 实际上这里使用的是: ```bash curl -I ``` 它发送的是 `HEAD` 请求,而 OpenList 对这个请求返回 `405 Method Not Allowed` 并不奇怪。 所以进一步测试普通 GET: ```bash curl -s -o /dev/null -w "HTTP: %{http_code}\nTime: %{time_total}s\n" https://open.fivk.cn ``` 结果: ```text HTTP: 200 Time: 0.033153s ``` 也就是: ```text HTTP: 200 耗时:0.033 秒 ``` 这说明: > **服务器访问 `open.fivk.cn` 的普通 HTTP 请求非常快。** 但是这里还有一个容易踩的坑: **GET 请求正常 ≠ 上传请求正常。** 因为照片上传涉及的是: ```text HTTP POST + 较大的 Request Body + Nginx → OpenList + OpenList → 115 ``` 和一个简单的 GET 请求完全不是一回事。 --- # 七、找到真正的宝塔反向代理配置 我的 `open.fivk.cn` 是使用宝塔配置的反向代理。 宝塔网站配置里面有: ```nginx include /www/server/panel/vhost/nginx/proxy/open.fivk.cn/*.conf; ``` 查看实际反向代理配置: ```bash ls -lah /www/server/panel/vhost/nginx/proxy/open.fivk.cn/ ``` 然后: ```bash cat /www/server/panel/vhost/nginx/proxy/open.fivk.cn/*.conf ``` 得到: ```nginx location ^~ / { proxy_pass http://127.0.0.1:5244; proxy_set_header Host open.fivk.cn; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_http_version 1.1; ... } ``` 这就确认了完整链路: ```text ChronoFrame ↓ https://open.fivk.cn ↓ Nginx ↓ 127.0.0.1:5244 ↓ OpenList ↓ 115 ``` --- # 八、真正的问题:Nginx 上传超时 这里就需要关注 Nginx 的几个配置: ```nginx client_max_body_size proxy_request_buffering proxy_connect_timeout proxy_send_timeout proxy_read_timeout ``` 其中最值得注意的是: ```nginx proxy_read_timeout ``` Nginx 默认的 `proxy_read_timeout` 通常是: ```text 60 秒 ``` 它并不是简单意义上的: > “整个请求只能执行 60 秒”。 而是 Nginx 等待上游响应数据时,两次读取之间允许等待的时间。 对于: ```text ChronoFrame ↓ Nginx ↓ OpenList ↓ 115 ``` 这样的链路,如果 OpenList/115 在某个阶段处理较慢,长时间没有返回数据,就可能导致 Nginx 主动关闭连接。 最终 ChronoFrame 收到: ```text 504 Gateway Time-out ``` 然后 ChronoFrame 的任务处理又进一步变成: ```text Preprocessing failed ``` 最后前端看到的就是: ```text Preprocessing timeout ``` 因此整个错误链可能实际上是: ```text 115 / OpenList 上传较慢 ↓ Nginx 等待上游时间过长 ↓ Nginx 返回 504 ↓ ChronoFrame OpenList 上传失败 ↓ Worker 任务失败 ↓ Preprocessing failed ↓ 前端显示 Preprocessing timeout ``` 这也解释了为什么: > **错误信息看起来像 ChronoFrame 自己处理超时,但底层日志实际上出现了 Nginx 504。** --- # 九、解决方案 最终我没有修改 ChronoFrame 源码,也没有降低 Worker 数量。 而是调整 OpenList 反向代理的 Nginx 配置。 在宝塔: ```text 网站 ↓ open.fivk.cn ↓ 配置文件 ``` 找到 `server {}`。 在: ```nginx root /www/wwwroot/open.fivk.cn; ``` 下面增加: ```nginx # OpenList 上传优化 client_max_body_size 512m; proxy_request_buffering off; proxy_connect_timeout 30s; proxy_send_timeout 600s; proxy_read_timeout 600s; ``` 最终类似: ```nginx server { listen 80; listen 443 ssl; http2 on; server_name open.fivk.cn; index index.php index.html index.htm default.php default.htm default.html; root /www/wwwroot/open.fivk.cn; # OpenList 上传优化 client_max_body_size 512m; proxy_request_buffering off; proxy_connect_timeout 30s; proxy_send_timeout 600s; proxy_read_timeout 600s; ... } ``` --- # 十、为什么是这几个参数? ## 1. `client_max_body_size` ```nginx client_max_body_size 512m; ``` Nginx 默认请求体限制比较小。 照片上传尤其是: - 手机原图 - RAW - 高分辨率 JPG - HEIC - 大尺寸视频 很容易超过默认限制。 设置: ```text 512 MB ``` 可以避免 Nginx 因为请求体过大直接拒绝上传。 --- ## 2. `proxy_request_buffering off` ```nginx proxy_request_buffering off; ``` 关闭反向代理请求体缓冲。 简单理解就是让上传数据更加直接地: ```text ChronoFrame ↓ Nginx ↓ OpenList ``` 而不是让 Nginx 尽可能先把请求体缓冲下来。 对于网盘上传这类场景比较合适。 --- ## 3. `proxy_read_timeout` ```nginx proxy_read_timeout 600s; ``` 将等待上游数据的时间提高到: ```text 600 秒 = 10 分钟 ``` 这也是这次解决问题最关键的参数之一。 --- ## 4. `proxy_send_timeout` ```nginx proxy_send_timeout 600s; ``` 允许 Nginx 向 OpenList 发送请求数据时有更长的时间。 --- ## 5. `proxy_connect_timeout` ```nginx proxy_connect_timeout 30s; ``` 设置 Nginx 连接 OpenList 的超时时间。 因为 OpenList 就运行在: ```text 127.0.0.1:5244 ``` 理论上这个连接应该非常快,所以这里设置 30 秒主要是作为保险。 --- # 十一、修改后不要直接重启 Nginx 修改完配置后,先执行: ```bash nginx -t ``` 如果看到: ```text syntax is ok test is successful ``` 说明配置语法没有问题。 然后: ```bash systemctl reload nginx ``` 使用 `reload` 就可以,不需要直接 `restart`。 --- # 十二、最终测试 修改完成后重新打开 ChronoFrame,上传照片。 我的实际测试结果是: > **原本频繁出现 `Preprocessing timeout` 的上传,在调整 Nginx 配置后恢复正常。** 因此这次问题基本可以确认不是单纯的: ```text ChronoFrame 图片处理能力不足 ``` 而是: ```text ChronoFrame ↓ OpenList ↓ Nginx ``` 这一层的上传请求超时问题。 --- # 十三、这次踩坑给我的几个经验 ## ① 不要只看前端错误提示 前端显示: ```text Preprocessing timeout ``` 不代表问题一定发生在: ```text Preprocessing ``` 一定要继续查看后端日志。 这次真正有价值的错误其实是: ```text OpenList upload failed status: 504 nginx ``` --- ## ② `504 Gateway Time-out` 一定要顺着代理链排查 出现: ```text 504 Gateway Time-out ``` 不要第一时间就认定是应用本身的问题。 应该沿着: ```text 客户端 ↓ Nginx ↓ 应用 ↓ 数据库 / 网盘 / API ``` 逐层排查。 尤其是使用: ```text Nginx + Docker + OpenList + 115 ``` 这种多层架构时,任何一层都有可能产生超时。 --- ## ③ GET 正常不代表上传正常 我的: ```bash curl https://open.fivk.cn ``` 只有: ```text 0.033153s ``` 但照片上传仍然会出现: ```text 504 ``` 原因是 GET 只证明: ```text HTTP 访问链路正常 ``` 并不能证明: ```text 大文件上传链路正常 ``` --- ## ④ 不要看到 Worker 多就直接降低 Worker ChronoFrame 当前: ```text workerCount: 5 ``` 确实可能增加并发上传压力。 但如果日志已经出现: ```text OpenList upload failed: 504 ``` 应该先把 Nginx/OpenList 这一层查清楚。 不要一看到: ```text 5 Worker ``` 就直接改成: ```text 1 Worker ``` 否则可能只是绕开问题,而不是解决问题。 --- # 十四、最终配置 对于我的: ```text ChronoFrame + OpenList + 115 + Nginx ``` 上传场景,目前最终使用: ```nginx # OpenList 上传优化 client_max_body_size 512m; proxy_request_buffering off; proxy_connect_timeout 30s; proxy_send_timeout 600s; proxy_read_timeout 600s; ``` 如果你也遇到类似: ```text Preprocessing timeout Preprocessing failed OpenList upload failed 504 Gateway Time-out fetch failed other side closed ``` 可以优先检查 Nginx 的反向代理配置。 --- # 总结 这次问题表面上是: ```text ChronoFrame Preprocessing timeout ``` 但真正的排查过程是: ```text Preprocessing timeout ↓ 查看 ChronoFrame 日志 ↓ 发现 OpenList upload failed ↓ HTTP 504 Gateway Time-out ↓ 确认 OpenList 通过 Nginx 反向代理 ↓ 检查宝塔 Nginx 配置 ↓ 调整上传大小和代理超时时间 ↓ 重新测试 ↓ 上传恢复正常 ``` **最终并没有修改 ChronoFrame 的 Worker,也没有修改 ChronoFrame 源码,而是通过调整 Nginx 反向代理参数解决了问题。** 这次也算是给自己提了个醒: > **遇到“应用层超时”,不要只盯着应用本身,尤其是涉及 Nginx、Docker、OpenList、115 这种多层代理链路时,要顺着整个请求链路去找真正的超时点。** --- ### 配置速查 ```nginx # OpenList 上传优化 client_max_body_size 512m; proxy_request_buffering off; proxy_connect_timeout 30s; proxy_send_timeout 600s; proxy_read_timeout 600s; ``` 检查配置: ```bash nginx -t ``` 重新加载: ```bash systemctl reload nginx ``` 查看最终加载配置: ```bash nginx -T 2>/dev/null | grep -E "client_max_body_size|proxy_request_buffering|proxy_connect_timeout|proxy_send_timeout|proxy_read_timeout" ``` 这样以后再遇到类似问题,就可以快速定位到底是**应用超时,还是反向代理超时**。 最后修改:2026 年 09 月 02 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏