使用MultipartEntityBuilder发请求却收到application/json的问题排查
问题:Apache HttpClient发送Multipart请求时Content-Type异常导致415错误?
客户端代码(Apache HttpClient)
CloseableHttpClient client = HttpClients.createDefault(); URIBuilder builder = new URIBuilder(uri); HttpPost request = new HttpPost(builder.build().toString()); MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); multipartEntityBuilder.addTextBody("user", username)); // 存在语法错误:多余的右括号 multipartEntityBuilder.addTextBody("pass", password)); // 存在语法错误:多余的右括号 multipartEntityBuilder.setContentType(ContentType.MULTIPART_FORM_DATA); multipartEntityBuilder.setCharset(StandardCharsets.UTF_8); request.setEntity(multipartEntityBuilder.build()); HttpResponse response = client.execute(request);
API端点代码(JAX-RS)
@POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.MULTIPART_FORM_DATA) public Response authenticateUser(@FormParam("user") String username, @FormParam("pass") String password) { try { String token = authenticate(username, password); return Response.ok(token).build(); } catch (Exception e) { return Response.status(Response.Status.FORBIDDEN).build(); } }
问题现象
API日志显示请求的Content-Type为application/json而非预期的multipart/form-data,触发415(不支持媒体类型)错误。但使用Spring RestTemplate的调用方式可正常请求该API。
原因分析
- 代码语法错误:HttpClient代码中
addTextBody方法调用末尾多了一个右括号,这会导致编译失败;若强行运行,会导致MultipartEntityBuilder构建实体异常,HttpClient可能 fallback 到默认的Content-Type(比如application/json)。 - 错误设置ContentType:手动调用
multipartEntityBuilder.setContentType(ContentType.MULTIPART_FORM_DATA)是冗余且可能产生干扰的——MultipartEntityBuilder默认会构建multipart/form-data类型的实体,且会自动生成必要的boundary参数(比如multipart/form-data; boundary=xxxx),手动设置会覆盖自动生成的完整Content-Type,甚至导致头信息不完整。 - 请求头被覆盖:若代码中存在拦截器或其他逻辑修改了
HttpPost的请求头,可能会将Content-Type替换为application/json。
排查与解决步骤
- 修复语法错误:移除
addTextBody调用末尾多余的右括号,确保代码正常编译:multipartEntityBuilder.addTextBody("user", username); multipartEntityBuilder.addTextBody("pass", password); - 移除冗余的ContentType设置:删除
multipartEntityBuilder.setContentType(ContentType.MULTIPART_FORM_DATA),让MultipartEntityBuilder自动生成包含boundary的完整Content-Type头。 - 验证实体的Content-Type:在设置请求实体前,打印实体的ContentType确认格式:
HttpEntity entity = multipartEntityBuilder.build(); System.out.println(entity.getContentType()); // 应为类似 multipart/form-data; boundary=... 的格式 - 检查请求拦截器:排查是否存在
HttpRequestInterceptor或其他逻辑修改了请求头,确保没有覆盖Content-Type。 - 升级HttpClient版本:若使用旧版本(如4.3及以下),可能存在
MultipartEntityBuilder的bug,建议升级到4.5.x及以上版本。
为什么RestTemplate可以正常工作
RestTemplate的处理逻辑更严谨:
- 显式设置
HttpHeaders的ContentType为MULTIPART_FORM_DATA,当请求体为MultiValueMap时,会自动使用MultipartFormHttpMessageConverter处理请求。 - 该转换器会自动生成合法的boundary参数,并构建包含boundary的完整
Content-Type头,确保请求头与请求体格式匹配,不会出现不兼容的情况。
内容的提问来源于stack exchange,提问作者simonalexander2005
相关产品推荐
相关产品推荐

