方法论与洞察

轻量级 WebApp 部署复盘:WebUploadApp

入档:2026-06-07 项目:WebUploadApp 轻量级文件上传页 场景:腾讯云 Ubuntu 服务器,协作者通过网页上传图片 / 视频到固定目录 性质:项目复盘 + 可复用部署方法


事实记录(不可修改区)


一句话

轻量级 Web 上传工具不是“Flask 页面能跑”就结束,真正的部署成败取决于四层同时对齐:上传目录、反向代理大小限制、后端超时、前端上传反馈。


本次工作流

  1. 本地先做最小 Flask 原型:文件类型白名单、大小限制、secure_filename、短 UUID 防重名、测试覆盖。
  2. 服务器部署采用 Gunicorn -> Nginx -> Basic Auth,上传目录固定到 /data/webupload/uploads
  3. 因本机 SSH 卡住,改用腾讯云 Web 终端粘贴部署脚本,降低接管成本。
  4. Caddy 占用 80 端口后,确认服务器无其他站点依赖,再停用 Caddy,让 Nginx 接管。
  5. 首次上传成功后,按实际用户体验补进度条和大文件配置。
  6. 进度条卡 100% 后,把上传接口改为 JSON 返回,前端只更新结果区,不再 document.write() 整页替换。

方法论沉淀

1. 部署先查端口占用,不要默认 Nginx 是唯一入口

核心:云服务器上 80 端口可能已被 Caddy、Apache、面板服务或手动进程占用;Nginx 配置正确不等于能启动。

来源:本次 nginx -t 成功,但 systemctl restart nginx 失败,日志显示 bind() to 0.0.0.0:80 failed,最终 ss -ltnp 查到 Caddy 占用 80。

验证状态:首次发现。

操作规则

  1. Nginx 启动失败时先跑 ss -ltnp | grep ':80'
  2. 如果是 Caddy / Apache,占用服务是否能停必须先判断,不要盲停生产站点。
  3. nginx -t 只证明语法正确,不证明端口可绑定。

边界:如果服务器已有正式网站,应改用现有 Caddy/Nginx 配置接入新应用,而不是停服务。

2. 大文件上传要同时改三层限制

核心:单改 Flask 的 MAX_CONTENT_LENGTH 不够;Nginx、Gunicorn、浏览器连接时间也会各自截断上传。

来源:上传视频时出现连接重置,后续通过放宽 client_max_body_size、Nginx 超时、Gunicorn --timeout、环境变量 UPLOAD_MAX_MB 后恢复。

验证状态:首次发现。

操作规则

  1. Flask:用环境变量控制 UPLOAD_MAX_MB,避免写死 100MB。
  2. Nginx:同步设置 client_max_body_sizeclient_body_timeoutproxy_read_timeout
  3. Gunicorn:设置 --timeout 900 这类足够长的上传窗口。
  4. 修改后用小图和大视频各测一次,只测小图不能证明大文件链路可用。

边界:2GB 只是临时协作阈值;更大文件应考虑分片上传、对象存储或专用传输工具。

3. 上传进度 100% 不等于服务端保存完成

核心:XHR 的 upload progress 只表示浏览器把请求体发完,不代表 Flask 已保存完成、也不代表页面已收到业务成功响应。

来源:页面进度条到 100% 后一直停留。前端提示应从“正在上传”切到“服务器正在保存”,再等待后端业务响应。

验证状态:首次发现。

操作规则

  1. 进度条到 100% 时显示“上传完成,服务器正在保存…”。
  2. 后端成功后再显示“上传成功”和保存文件名。
  3. 对大文件上传,必须区分“传输完成”和“保存确认”两个阶段。

边界:如果要显示服务端保存进度,需要更复杂的分片/任务状态机制;普通 Flask 单请求无法天然提供服务端保存百分比。

4. 上传接口返回 JSON,比整页 HTML 替换更稳

核心:有进度条的表单上传应让 /upload 返回 JSON,由前端局部更新结果;不要在 XHR 完成后 document.write(xhr.responseText)

来源:初版进度条用 XHR 上传后整页写回 HTML,出现卡在 100% 的体验问题。改成 JSON 后,页面可稳定显示成功 / 错误结果。

验证状态:首次发现。

操作规则

  1. 页面 GET / 返回 HTML。
  2. 上传 POST /upload 返回 { ok, filename }{ ok:false, error }
  3. 前端用 onload / onerror / ontimeout 分别处理成功、连接中断和超时。
  4. 上传按钮在请求中禁用,请求结束后恢复。

边界:如果项目坚持无 JS 表单提交,则可继续返回 HTML;但一旦需要进度条,就应切换 JSON 接口。

5. Agent 不能直接 SSH 时,Web 终端粘贴脚本是有效降级方案

核心:远程接管失败不等于部署失败;把部署动作收敛成一段可复制脚本,可以绕开 SSH、SFTP、网页终端控制权等卡点。

来源:本机到服务器 SSH 端口可达,但 OpenSSH 登录超时;最终通过腾讯云 Web 终端粘贴脚本完成部署和后续修复。

验证状态:首次发现。

操作规则

  1. 优先尝试 SSH key 接管,失败后不要无限诊断。
  2. 降级为“用户粘贴一次脚本,Agent 根据输出继续修复”。
  3. 脚本必须幂等,能重复执行关键步骤,不依赖交互输入。
  4. 出错后只要求用户贴关键日志,不让用户猜。

边界:涉及删除、停服务、覆盖配置时必须先确认影响面;脚本不要默认清空未知目录。


下次同类任务行动清单


关联文档

类型/协作工具链类型/工作流方法论工具/Flask工具/Nginx