Spring OpenAPI生成客户端:无filename的MultipartFile接收异常问题
我用OpenAPI生成的Spring客户端处理MultipartFile对象,大部分场景运行正常,但调用接口时,若Content-Disposition头缺少filename属性,请求就会失败;只要添加filename属性(哪怕值为空),请求就能正常执行。
错误请求头示例:
Content-Disposition: form-data; name="file"
正常请求头示例:
Content-Disposition: form-data; name="file"; filename=
由于需要在单次请求中同时上传文件及附加元数据,必须依赖multipart方式,无法更换上传方式。请问需调整哪些配置?或该场景是否不被支持?
1. 调整OpenAPI配置文件
在OpenAPI的yaml/json定义中,针对multipart类型的请求,给对应file参数显式指定filename为空的默认请求头:
paths: /upload: post: requestBody: content: multipart/form-data: schema: type: object properties: file: type: string format: binary encoding: file: headers: Content-Disposition: schema: type: string default: "form-data; name=\"file\"; filename="
重新生成客户端代码后,请求会自动带上包含空值filename的头。
2. 自定义Spring MultipartResolver
若无法修改OpenAPI配置,可自定义Multipart解析器,允许不带filename的multipart文件项:
public class CustomMultipartResolver extends StandardServletMultipartResolver { @Override protected MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException { return new CustomMultipartHttpServletRequest(request); } private static class CustomMultipartHttpServletRequest extends StandardMultipartHttpServletRequest { public CustomMultipartHttpServletRequest(HttpServletRequest request) throws MultipartException { super(request); } @Override protected void parseRequest(HttpServletRequest request) { try { Collection<Part> parts = request.getParts(); for (Part part : parts) { String disposition = part.getHeader(HttpHeaders.CONTENT_DISPOSITION); if (disposition != null && !disposition.contains("filename=")) { disposition += "; filename="; // 通过反射修改Part的请求头 Field headersField = part.getClass().getDeclaredField("headers"); headersField.setAccessible(true); Map<String, List<String>> headers = (Map<String, List<String>>) headersField.get(part); headers.put(HttpHeaders.CONTENT_DISPOSITION, Collections.singletonList(disposition)); } } super.parseRequest(request); } catch (Exception e) { throw new MultipartException("解析multipart请求失败", e); } } } }
然后在Spring配置中注册该解析器:
@Configuration public class MultipartConfig { @Bean public MultipartResolver multipartResolver() { return new CustomMultipartResolver(); } }
3. 修改OpenAPI生成器模板
如果使用OpenAPI Generator的Java模板,可修改multipartForm.mustache模板,强制给file参数添加空filename的请求头:
Content-Disposition: form-data; name="{{paramName}}"; filename=
重新生成客户端代码后,所有multipart文件请求都会自动带上该头。
4. 直接修改生成的客户端代码
若上述方式都不方便,可直接修改生成的客户端代码中构建请求的逻辑,手动添加空filename的头:
// 示例:修改Multipart请求构建逻辑 MultipartBody.Builder builder = MultipartBody.builder(); // 显式指定空filename builder.addFormDataPart("file", "", file.getInputStream(), MediaType.APPLICATION_OCTET_STREAM);
该场景是被支持的,问题根源在于Spring默认的Multipart解析器要求文件类型的multipart项必须包含filename属性(即使为空),而OpenAPI生成的客户端在部分场景下未自动添加该属性。通过上述任一配置调整,均可解决问题。
内容的提问来源于stack exchange,提问作者Kaze

