graphql-spring-boot上传二进制文件时请求部件为空求助
我来帮你梳理下这个问题的排查思路和解决方案——你遇到的核心问题是Spring Boot在处理GraphQL的multipart/form-data请求时,没有正确解析请求中的文件部分,导致你在GraphQLContext里拿不到Part对象。下面是一步步的解决步骤:
1. 先修正最容易踩坑的配置前缀
你在application.yml里用了spring.http.multipart这个配置前缀,但Spring Boot 2.x及以后版本,multipart的配置前缀已经改成spring.servlet.multipart了!旧前缀的配置根本不会生效,这大概率是你拿不到parts的主要原因。
修正后的application.yml配置:
spring: servlet: multipart: enabled: true file-size-threshold: 10MB location: /tmp max-file-size: 10MB max-request-size: 15MB resolve-lazily: false
2. 移除冲突的自定义Initializer
你写的MyInitializer继承了AbstractAnnotationConfigDispatcherServletInitializer,但Spring Boot本身已经自动配置了DispatcherServlet,手动添加这个类会覆盖默认配置,反而导致multipart支持失效。直接删掉这个类就好,Spring Boot的自动配置足够处理DispatcherServlet的注册和multipart配置。
3. 调整GraphQL Context和Resolver的文件获取逻辑
确保你在正确的时机获取文件——可以尝试在GraphQL的Mutation Resolver里直接注入HttpServletRequest,而不是只在GraphQLContextBuilder里处理,这样能避免上下文传递时的问题。
示例代码:
@Component public class ProjectMutationResolver implements GraphQLMutationResolver { @Autowired private ProjectRepository projectRepository; public Project createProject(ProjectInput input, @Context HttpServletRequest request) throws IOException, ServletException { // 尝试获取上传的文件 Part filePart = request.getPart("file"); if (filePart != null && filePart.getSize() > 0) { // 保存文件到本地,并记录路径 String filePath = saveUploadedFile(filePart); input.setFileUrl(filePath); // 把路径绑定到你的输入对象里 } // 执行GraphQL的业务逻辑,保存Project数据 Project project = convertInputToEntity(input); return projectRepository.save(project); } // 工具方法:保存上传的文件到指定目录 private String saveUploadedFile(Part filePart) throws IOException { String uploadDir = "/tmp/graphql-uploads"; File dir = new File(uploadDir); if (!dir.exists()) { dir.mkdirs(); } String fileName = UUID.randomUUID() + "_" + filePart.getSubmittedFileName(); // 避免文件名重复 String fullPath = uploadDir + File.separator + fileName; try (InputStream inputStream = filePart.getInputStream(); OutputStream outputStream = new FileOutputStream(fullPath)) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } } return fullPath; } }
4. 调试验证:添加Multipart请求调试Filter
如果还是拿不到parts,可以加一个Filter来确认请求是否被正确识别为multipart类型,以及服务器是否能解析到parts:
@Component public class MultipartDebugFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; System.out.println("请求Content-Type: " + req.getContentType()); System.out.println("是否为Multipart请求: " + req.isMultipartContent()); if (req.isMultipartContent()) { Collection<Part> parts = req.getParts(); System.out.println("解析到的Part数量: " + parts.size()); for (Part part : parts) { System.out.println("Part名称: " + part.getName() + ", 文件名: " + part.getSubmittedFileName()); } } chain.doFilter(request, response); } }
启动项目后发送请求,查看控制台输出:
- 如果显示
是否为Multipart请求: false,说明请求本身有问题,或者multipart配置仍未生效; - 如果能看到file的Part信息,说明问题出在GraphQL上下文传递环节,此时可以直接在Resolver里获取文件。
5. 确认GraphQL Spring Boot Starter版本
建议使用最新稳定版的graphql-spring-boot-starter(比如5.x及以上),旧版本对multipart请求的支持可能存在bug。你可以在pom.xml(或build.gradle)里检查版本:
<dependency> <groupId>com.graphql-java-kickstart</groupId> <artifactId>graphql-spring-boot-starter</artifactId> <version>12.0.0</version> <!-- 替换为最新稳定版 --> </dependency>
按照上面的步骤调整后,应该就能正常获取到上传的文件并保存路径到GraphQL数据里了。
内容的提问来源于stack exchange,提问作者Mike

