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
相关产品推荐
相关产品推荐

