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

Java Rest文件上传转发异常:上传端点转发文件至后端点接收为空

问题描述

我需要实现一个文件上传转发端点,流程如下:

[前端] ----(文件)----> [UploadResource] ----(相同文件)----> [ApiServiceResource]

目前第一个端点能正常接收文件,但转发到第二个端点时,第二个端点收到的文件列表为空。

相关代码如下:

导入包

import java.util.List;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.RestForm;
import org.jboss.resteasy.reactive.multipart.FileUpload;
import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

UploadResource类

@Path("/v1/upload")
public class UploadResource {
  @Inject
  @RestClient
  ApiService apiService;

  @POST
  @Consumes(MediaType.MULTIPART_FORM_DATA)
  @Produces(MediaType.TEXT_PLAIN)
  public Response uploadFiles(@RestForm(FileUpload.ALL) @PartType(MediaType.APPLICATION_OCTET_STREAM) List<FileUpload> files) {
    System.out.println("endpoint 'v1/upload' received " + files.size() + " files");
    apiService.receiveFiles(files);
    return Response.ok().build();
  }
}

ApiService接口

@RegisterRestClient(configKey = "api-service")
public interface ApiService {
  @POST
  @Path("v1/receivefiles")
  @Consumes(MediaType.MULTIPART_FORM_DATA)
  @Produces(MediaType.TEXT_PLAIN)
  Response receiveFiles(@RestForm(FileUpload.ALL) @PartType(MediaType.APPLICATION_OCTET_STREAM) List<FileUpload> files);
}

ApiServiceResource类

@Path("/api-service")
public class ApiServiceResource {
  @POST
  @Path("v1/receivefiles")
  @Consumes(MediaType.MULTIPART_FORM_DATA)
  @Produces(MediaType.TEXT_PLAIN)
  public Response receiveFiles(@RestForm(FileUpload.ALL) @PartType(MediaType.APPLICATION_OCTET_STREAM) List<FileUpload> files) {
    System.out.println("endpoint 'api-service/v1/receivefiles' received " + files.size() + " files");
    return Response.ok().build();
  }
}

控制台输出

发送包含3个文件的POST请求到.../v1/upload后,控制台打印:

endpoint 'v1/upload' received 3 files
endpoint 'api-service/v1/receivefiles' received 0 files

注意:直接向api-service/v1/receivefiles发送请求时功能正常。


解决方案

问题核心是FileUpload的特性限制:它是Quarkus Reactive环境下的流式临时文件对象,内容仅能被读取一次,且MicroProfile Rest Client无法直接将其序列化为符合规范的multipart/form-data请求体。需要手动构建multipart请求来完成转发:

步骤1:修改ApiService接口

将参数改为MultipartFormDataOutput,让RestClient能正确处理手动构建的multipart请求:

import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
import jakarta.ws.rs.core.Response;

@RegisterRestClient(configKey = "api-service")
public interface ApiService {
  @POST
  @Path("v1/receivefiles")
  @Consumes(MediaType.MULTIPART_FORM_DATA)
  @Produces(MediaType.TEXT_PLAIN)
  Response receiveFiles(MultipartFormDataOutput formData);
}

步骤2:修改UploadResource实现

读取每个FileUpload的内容,手动构建multipart表单后转发:

import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
import java.io.IOException;

@Path("/v1/upload")
public class UploadResource {
  @Inject
  @RestClient
  ApiService apiService;

  @POST
  @Consumes(MediaType.MULTIPART_FORM_DATA)
  @Produces(MediaType.TEXT_PLAIN)
  public Response uploadFiles(@RestForm(FileUpload.ALL) @PartType(MediaType.APPLICATION_OCTET_STREAM) List<FileUpload> files) throws IOException {
    System.out.println("endpoint 'v1/upload' received " + files.size() + " files");
    
    MultipartFormDataOutput formData = new MultipartFormDataOutput();
    for (FileUpload file : files) {
      // 读取文件内容为字节数组
      byte[] fileContent = file.uploadedFile().readAllBytes();
      // 将文件添加到multipart表单,使用原文件名作为表单字段名
      formData.addFormData(file.fileName(), fileContent, MediaType.APPLICATION_OCTET_STREAM_TYPE);
    }
    
    apiService.receiveFiles(formData);
    return Response.ok().build();
  }
}

步骤3:保持ApiServiceResource不变

原有的接收端代码无需修改,它能正常解析手动构建的multipart请求。


原理说明
  • FileUpload的流式设计导致其内容无法被重复读取或直接序列化传递给RestClient;
  • 通过MultipartFormDataOutput手动构建multipart请求,将文件内容转换为字节数组后封装,确保RestClient生成符合HTTP规范的请求体,让接收端能正确解析出文件列表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 23:12:04