You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS前端上传JSON文件至Scala ZHttp后端:提取纯JSON内容

问题根源

当你用FormData构造请求时,哪怕手动设置Content-Type为application/json,浏览器依然会自动将请求头改为multipart/form-data并添加WebKitFormBoundary边界标识——因为FormData本身就是为多部分表单数据设计的。后端收到的是完整的multipart格式请求体,不是纯JSON字符串,直接用JSON解析器读取自然会报错。

解决方案

根据你的实际需求,有两种处理方式:

方案1:直接提交JSON数据(无需上传文件)

如果你的需求只是传递{"name": "John", "age": 35}这段JSON内容,完全没必要用FormData,直接发送JSON字符串即可:

const jsonData = {"name": "John", "age": 35};
fetch('/your-api-endpoint', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(jsonData),
})
.then(res => res.json())
.catch(err => console.error('请求失败:', err));

这种方式后端能直接解析纯JSON体,你之前测试过这种情况是正常的,适合仅提交JSON数据的场景。

方案2:后端解析Multipart请求(确实需要上传JSON文件)

如果你的需求是让用户上传本地JSON文件,那前端用FormData是正确的,但后端需要处理multipart/form-data类型的请求,先提取文件内容再解析JSON。

在Scala zhttp中可以这样实现:

import zhttp.http._
import zhttp.service.Server
import zio._
import io.circe.parser

object JsonFileUploadServer extends ZIOAppDefault {
  val uploadApp: HttpApp[Any, Throwable] = Http.collectZIO[Request] {
    case req@Method.POST -> !! / "upload-json-file" =>
      req.multipart.flatMap { multipart =>
        // 匹配前端FormData中设置的文件字段名,这里假设是"jsonFile"
        multipart.files.find(_.name == "jsonFile") match {
          case Some(file) =>
            // 读取文件内容为字符串,再解析JSON
            file.content.asString.flatMap { fileContent =>
              parser.parse(fileContent)
                .fold(
                  parseErr => ZIO.succeed(Response.text(s"JSON解析失败: ${parseErr.getMessage}").setStatus(Status.BadRequest)),
                  json => ZIO.succeed(Response.json(json.toString()))
                )
            }
          case None =>
            ZIO.succeed(Response.text("未找到名为jsonFile的上传文件").setStatus(Status.BadRequest))
        }
      }
  }

  override val run = Server.start(8080, uploadApp)
}

对应的前端上传代码(无需手动设置Content-Type):

// 假设页面中有<input type="file" id="jsonFileInput" accept=".json">
const fileInput = document.getElementById('jsonFileInput');
const formData = new FormData();
formData.append('jsonFile', fileInput.files[0]);

fetch('/upload-json-file', {
  method: 'POST',
  body: formData, // 浏览器会自动添加正确的multipart请求头
})
.then(res => res.text())
.catch(err => console.error('上传失败:', err));

内容的提问来源于stack exchange,提问作者Aleksey N Yakushev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 01:50:21