feign技巧 - form方式传值。
0. 文章目录
1. 前言
直接正题。 如何使用feign进行fom表单方式的请求调用,以及其中的注意事项。
2. 调用样例
// =============================================== feign调用端
// 注意事项:
// 1. 两个参数都要使用@RequestPart注解进行标注.
// 2. POST请求.
// 3. consumes属性配置为必选.
// 4. 代表参数载体对象的params字段, 不能存在继承关系, 所有字段都必须直接定义在KDeployParams中. 如果存在基类, 那么处理流程中,只有在`KDeployParams`中直接定义的字段才能被正确解析并传递给服务端,基类的字段不会被feign解析传递.
@PostMapping(value = "/projectB/postWithFormData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String postWithFormData(@RequestPart("file") MultipartFile file, @RequestPart KDeployParams params);
// =============================================== 对应的服务端
// 注意事项:
// 1. 第二个参数params前面没有任何注解, 或者使用@ModelAttribute。千万不要使用@RequestPart.
@PostMapping("/projectB/postWithFormData")
public String postWithFormData(@RequestPart(required = false, name = "file") MultipartFile file,
KDeployParams params) throws InterruptedException, IOException { ... }
3. 原理解析
分为两部分 —— 发送端的feign,以及服务端的SpringMVC。
3.1 feign端序列化参数
整条请求链路中,feign端的调用层级最终会来到位于feign-form-xx.jar中的MultipartFormContentProcessor.process (...)
。
3.2 SpringMVC服务端解析参数
针对上文例子中,在服务端接收层面,SpringMVC中负责传递过来的参数还原/反序列化为KDeployParams
的是ServletModelAttributeMethodProcessor
(该类实现了大名鼎鼎的HandlerMethodArgumentResolver
)。
3.3 补充 - 继承关系不会被传递的原因
PojoUtil的坑,下面这里只会检索出当前类直接声明的字段。
3.4 补充 - 不能使用GET
否则报如下错误:
4. 补充样例 - 上传文件时使用非MultipartFile
类型作为方法参数
// =============================== 方法一
// 1. 注意注解依然得是@RequestPart.
// 2. 处理File类型的源码为: SingleFileWriter.java
// 3. 使用样例: 略
@PostMapping(value = "/projectB/postWithFormData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String postWithFileParams(@RequestPart("file") File file, @RequestPart KDeployParams params);
// =============================== 方法二
// 1. 注意注解依然得是@RequestPart.
// 2. 处理FormData类型的源码为: FormDataWriter.java
// 3. 使用样例: feignDemo.postWithFileParams3(new FormData("application/octet-stream", "121.txt", FileUtil.readBytes(file)), kDeployParams));
// 4. 参考自: https://stackoverflow.com/questions/56526236/upload-data-file-as-byte-array-with-feign
@PostMapping(value = "/projectB/postWithFormData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String postWithFileParams3(@RequestPart("file") FormData file, @RequestPart KDeployParams params);
// =============================== 注意:
// 1. 服务端代码不需要变化, 依然使用 MultipartFile类型进行接收。
5. 总结
神在细节之中。
细节是魔鬼。