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

Java服务端如何解析multipart/form-data请求中的文件?

服务端解析Multipart文件的解决方案

你的客户端已经正确发送了multipart/form-data格式的文件,但当前服务端直接通过BufferedReader读取输入流的方式无法解析这种带边界分隔的二进制混合数据,以下是两种可行的解决方法:


方案1:使用JAX-RS原生@FormDataParam注解(推荐)

因为你的服务端基于JAX-RS(从@POST、@Path注解判断),可以直接利用框架的Multipart支持来简化文件接收:

步骤1:引入Multipart依赖

如果用Jersey作为JAX-RS实现,添加Maven依赖:

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-multipart</artifactId>
    <version>对应你的Jersey版本</version>
</dependency>

同时在你的JAX-RS应用类中注册MultipartFeature:

public class YourApplication extends ResourceConfig {
    public YourApplication() {
        register(MultipartFeature.class);
        // 其他资源注册
    }
}

步骤2:修改服务端代码

直接通过注解获取文件流、文件信息,以及请求头/表单参数:

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import javax.ws.rs.HeaderParam;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

@POST
@Path("/createRequest")
@Consumes("multipart/form-data")
public Response createRequest(
        // 接收上传的文件流和文件元数据
        @FormDataParam("file") InputStream fileInputStream,
        @FormDataParam("file") FormDataContentDisposition fileDisposition,
        // 从请求头获取你传递的id和lastModified
        @HeaderParam("id") String requestId,
        @HeaderParam("lastModified") String lastUpdated) {

    try {
        // 获取客户端传递的文件名
        String fileName = fileDisposition.getFileName();
        // 将文件保存到指定路径
        Files.copy(fileInputStream, Paths.get("你的保存目录/" + fileName), StandardCopyOption.REPLACE_EXISTING);
        
        // 这里可以处理requestId和lastUpdated参数
        System.out.println("请求ID:" + requestId);
        System.out.println("最后修改时间:" + lastUpdated);
        
        return Response.ok("文件接收成功:" + fileName).build();
    } catch (Exception e) {
        e.printStackTrace();
        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("文件接收失败").build();
    }
}

方案2:手动解析Multipart数据(不推荐)

如果不想依赖框架的Multipart支持,可以手动根据请求头中的边界值拆分请求体,但这种方式需要处理二进制数据的编码问题,实现繁琐:

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Context;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.apache.commons.io.IOUtils;

@POST
@Path("/createRequest")
public Response createRequest(@Context HttpServletRequest request) {
    try {
        String contentType = request.getContentType();
        if (!contentType.startsWith("multipart/form-data")) {
            return Response.status(Response.Status.BAD_REQUEST).entity("非法请求格式").build();
        }
        
        // 提取boundary值
        String boundary = "--" + contentType.split("boundary=")[1];
        InputStream inputStream = request.getInputStream();
        byte[] requestBytes = IOUtils.toByteArray(inputStream);
        
        // 拆分multipart各部分
        String[] parts = new String(requestBytes, "UTF-8").split(boundary);
        for (String part : parts) {
            if (part.contains("Content-Disposition: form-data; name=\"file\"")) {
                // 定位文件二进制数据的起始和结束位置
                int start = part.indexOf("\r\n\r\n") + 4;
                int end = part.lastIndexOf("\r\n--");
                if (start > 0 && end > start) {
                    // 提取文件字节并保存
                    byte[] fileBytes = new byte[end - start];
                    System.arraycopy(requestBytes, start, fileBytes, 0, end - start);
                    Files.write(Paths.get("你的保存目录/testFile.xlsx"), fileBytes);
                    break;
                }
            }
        }
        return Response.ok("文件接收成功").build();
    } catch (Exception e) {
        e.printStackTrace();
        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
    }
}

客户端代码修正

当前客户端缺少Multipart请求的结束边界标记,需要在写入文件后添加:

// 写完文件字节后添加
outStream.writeBytes(crlf);
outStream.writeBytes(twoHyphens + boundary + twoHyphens + crlf); // 结束边界

否则服务端可能会认为请求不完整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 13:10:29