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

React向Spring Boot提交JSON+文件表单数据报错排查

React表单提交Spring Boot接口出现application/octet-stream不支持错误的解决

问题背景

基于React.js MFE和Spring Boot微服务开发应用,React表单包含多个输入字段及6个待上传文件,提交至Spring Boot REST控制器时返回Content type 'application/octet-stream' not supported错误,但使用Postman提交相同数据可正常运行。

React提交代码

const handleSubmit = (e) => {
  e.preventDefault();

  setErrorMessage(null);
  setErrorMessageForiEMessaggi(null);

  if (selectedFori.length == 0 || selectedMaterie.length == 0) {
    setErrorMessageForiEMessaggi(
      "Bisogna selezionare almeno un foro e una materia"
    );
  } else {
    const data = new FormData();

    //aggiungo i valori delle select
    const formDataAggiornato = {
      ...formData,
      ordine: selectedOrdine,
      regioneSedeStudio: selectedRegioneSedeStudio,
      provinciaSedeStudio: selectedProvinciaSedeStudio,
      comuneSedeStudio: selectedComuneSedeStudio,
      materia1: selectedMaterie.length >= 1 ? selectedMaterie[0] : null,
      materia2: selectedMaterie.length >= 2 ? selectedMaterie[1] : null,
      materia3: selectedMaterie.length == 3 ? selectedMaterie[2] : null,
      foro1: selectedFori.length >= 1 ? selectedFori[0] : null,
      foro2: selectedFori.length >= 2 ? selectedFori[1] : null,
      foro3: selectedFori.length == 3 ? selectedFori[2] : null,
    };

    for (const [key, file] of Object.entries(prevFiles)) {
      if (file) {
        const newFileName = file?.name
          ? `${key}_${file.name}`
          : `${key}_${file}`;
        console.log("nome file", newFileName);
        const renamedFile = new File([file], newFileName, {
          type: file.type,
        });
        data.append(`files`, renamedFile);
      }
    }

    data.append("avvocato", JSON.stringify(formDataAggiornato));

    const requestOptions = {
      headers: { Authorization: `Bearer ${token}` },
      method: "POST",
      body: data,
    };

    // Effettua la richiesta POST utilizzando fetch
    fetch(url + API_PATH, requestOptions).then((response) => {
      if (response.ok) {
        console.log(response);

        //chiudo modale
        toggleModal(!isOpen);

        //svuoto domanda
        setDomanda(null);

        //ricarico lista domande
        reloadListaDomande();

        //stampo messaggio successo in TableDomanda
        setSuccessMessageTable(
          domanda?.id
            ? "Modifica avvenuta con successo!"
            : "Elemento creato correttamente"
        );

        setErrorMessage(null);
        setErrorMessageForiEMessaggi(null);

        return response.json();
      } else {
        setErrorMessage(
          "Errore durante il salvataggio dei dati, ricaricare la pagina"
        );
        console.log(response);
      }
    });
  }
};

Spring Boot控制器代码

@Operation(summary = "salva l'avvocato", tags = {"Avvocati"})
@PreAuthorize("hasRole('userfo')")
@PostMapping(value = "", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE})
@ApiResponse(responseCode = "201")
public ResponseEntity<AvvocatoDto> salvaAvvocato(@RequestPart("avvocato") @Valid AvvocatoDto dto, @RequestPart(value = "files", required = false) List<MultipartFile> files) throws IOException, ForbiddenOpException {

错误信息

2024-07-15 13:06:33.692 ERROR 1 --- [nio-8081-exec-5] c.c.a.exception.ExceptionsHandler        : GENERIC ERROR : Content type 'application/octet-stream' not supported

org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported
        at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:211) ~[spring-webmvc-5.3.27.jar!/:5.3.27]
        at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:140) ~[spring-webmvc-5.3.27.jar!/:5.3.27]
        at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122) ~[spring-web-5.3.27.jar!/:5.3.27]
        at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179) ~[spring-web-5.3.27.jar!/:5.3.27]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146) ~[spring-web-5.3.27.jar!/:5.3.27]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.27.jar!/:5.3.27]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.27.jar!/:5.3.27]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.27.jar!/:5.3.27]

问题原因

核心问题在于React端添加avvocato字段时,直接传递JSON字符串但未指定Content-Type,导致Spring Boot无法识别该字段的格式,默认将其判定为application/octet-stream,而控制器期望接收的是JSON类型的AvvocatoDto对象。

Postman提交正常是因为Postman会自动为JSON类型的表单字段设置Content-Type: application/json请求头,但React的FormData.append()方法默认不会为字符串类型的JSON数据添加该头信息。

另外,文件处理部分若file.type为空,新创建的File对象会缺失类型标识,也可能触发类似的类型识别错误。

解决方案

1. 为JSON字段指定正确的Content-Type

修改React代码中添加avvocato字段的逻辑,使用Blob包装JSON字符串并明确指定MIME类型:

// 替换原有的data.append("avvocato", JSON.stringify(formDataAggiornato));
const avvocatoBlob = new Blob([JSON.stringify(formDataAggiornato)], { type: 'application/json' });
data.append("avvocato", avvocatoBlob);

2. 为文件设置默认类型(可选)

若存在文件类型为空的情况,为新创建的File对象添加默认类型,避免类型缺失:

const renamedFile = new File([file], newFileName, {
  type: file.type || 'application/octet-stream', // 补充默认类型
});

验证修改

完成上述修改后重新提交表单,Spring Boot就能正确识别avvocato字段为JSON类型,同时文件的Content-Type也能正常传递,即可解决该错误。

内容的提问来源于stack exchange,提问作者Andrea

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:53:22