文件上传接口 404 故障排查记录,接口能正常访问

问题现象

  • 文件上传流程:压缩完成后,点击上传按钮,分片上传接口返回 404 Not Found
  • 错误信息POST /prod-api/service/uploadRecord/chunk 404 (Not Found),响应体为 Nginx 默认 404 HTML 页面
  • 异常点:其他业务接口(如查询、初始化)调用正常,唯独上传相关的 POST 请求返回 404
  • 初步判断:接口路径本身存在(初始化、检查接口可正常调用),但带有文件数据的 multipart 请求被拦截

排查过程

第一阶段:前端代码加日志

1. request.js 全局拦截器加调试日志

src/utils/request.js 的请求拦截器中,针对包含 uploadRecord 的请求打印详细配置:

  • 请求方法(method)
  • baseURL 与最终拼接 URL
  • 请求头(headers)
  • data 类型(是否为 FormData)
  • Content-Type 是否被正确设置

同时增加保护逻辑:若 dataFormData,显式删除 Content-Type header,强制让浏览器自动设置为 multipart/form-data,排除 axios 全局 application/json 默认值干扰。

2. cdList.js chunk 接口加日志

src/api/cdList.jschunk() 函数中,调用前打印:

  • VITE_HOST_UPLOAD_URL 环境变量值
  • 拼接后的完整请求地址
  • 入参数据类型
3. FileUploader 组件加全流程日志

src/components/FileUploader/index.vuehandleUpload 中,对以下节点上报/打印日志:

  • 开始上传流程
  • 文件 MD5 检查
  • 初始化上传
  • 分片上传(每片开始/成功/失败)
  • 合并分片
  • 保存报告记录
  • 整体成功/失败

并在分片上传失败时,自动触发 fetch 降级对比测试,同时用 fetch 发送完全相同的 FormData,对比 axios 与 fetch 的差异。


第二阶段:浏览器独立测试页面

编写独立的 HTML 测试页面(不依赖项目代码),在浏览器环境中直接对接口进行控制变量测试:

测试项 目的
fetch 空 POST 验证接口路径是否存在
fetch FormData(假 Blob) 验证不带文件名的表单提交
axios FormData(假 Blob) 验证 axios 库本身是否有特殊行为
axios + 强制 json Content-Type 验证 Content-Type 错误时的表现
fetch 上传真实 ZIP 文件 模拟真实场景(带真实文件名、文件大小、二进制内容)
axios 上传真实 ZIP 文件 与 fetch 真实文件测试做对比

测试页面支持填入 Authorization Token,可对比带 Token不带 Token 时的服务器响应差异。


第三阶段:对比验证

关键发现 1:URL 与路径本身没有问题
  • 空 POST 请求可正常到达服务器(返回 400 参数校验错误,而非 404)
  • /service/uploadRecord/check/service/uploadRecord/init 等接口调用正常
  • 说明接口路径在服务器上是存在的
关键发现 2:axios vs fetch 行为一致
  • 在独立测试页面中,fetch 和 axios 只要携带真实文件,都会返回 404
  • 排除 axios 库本身(如 Content-Type 污染、header 自动添加等)导致的问题
  • 确认问题在服务器层,而非前端代码层
关键发现 3:带文件即 404,不带文件即正常
  • 不携带 chunk 文件字段的请求 → 正常返回(400 或 200)
  • 携带 chunk 文件字段(无论 fetch 还是 axios)→ 返回 404
  • 最终定位:Nginx 层面对 multipart/form-data 上传请求做了拦截或限制

根因结论

Nginx 服务器配置对文件上传请求做了限制,具体表现为:

  • 普通 JSON 接口请求 → 正常转发到后端服务
  • multipart/form-data 文件上传请求 → Nginx 直接返回 404,请求未到达后端应用服务

可能的具体原因(需运维/后端确认):

  1. Nginx client_max_body_size 配置为 0 或未开启,导致直接拒绝上传请求
  2. Nginx 配置了基于 Content-Type 或请求体的访问控制规则,拦截了 multipart 请求
  3. Nginx 缺少对应 location 的 proxy_pass 配置,或上传流量被路由到了不存在该接口的 upstream
  4. 安全模块(如 WAF、ModSecurity)规则拦截了文件上传

后续修复建议

  1. 运维侧:检查 Nginx 配置中 client_max_body_size 是否设置为合理值(建议 >= 100M,与业务分片大小匹配)
  2. 运维侧:确认上传接口的 location 块是否正确配置了 proxy_pass,且上传流量被转发到正确的后端服务
  3. 运维侧:检查 Nginx 访问日志(access.log),确认 404 是由 Nginx 本身返回还是后端返回
  4. 后端侧:确认上传服务是否部署在正确的 upstream 节点上,与不带认证的公共服务节点区分开

经验总结

  1. 前端排查三板斧:加日志 → 独立测试页 → 控制变量对比
  2. 当 fetch 和 axios 表现一致时,问题基本可锁定在服务器/网络层,无需在前端代码上过度排查
  3. 404 不一定代表"路径不存在":Nginx 可能因请求特征(如 Content-Type、Body 大小)主动拒绝请求并返回 404
  4. 真实文件测试很关键:用假 Blob 测试可能无法触发服务器对文件上传的限制策略,必须使用真实文件对象

相关代码改动(排查期间)

以下文件在排查过程中被修改用于加日志或测试,修复完成后可根据需要保留或移除调试代码:

文件 改动说明
src/utils/request.js 增加上传请求调试日志 + FormData Content-Type 保护
src/api/cdList.js chunk() 函数增加调用前日志
src/components/FileUploader/index.vue 上传全流程日志 + fetch 降级对比测试
tests/test-upload-chunk.html 浏览器独立测试页面(fetch/axios/真实文件上传对比)
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐