The following interface should be enough to handle multipart form requests:
@FeignClient(url = "http://localhost:8080")
public interface SpringFeignTestInterface {
@RequestMapping(value = "/upload/{folder}", method = POST)
public ResponseEntity<UploadInfo> upload(@PathVariable("folder") String folder, @RequestParam("file") MultipartFile file, @RequestParam("metadata") UploadMetadata metadata) ;
}
It doesn't work, since the @RequestParam annotation (processed by this code) does not trigger multipart form generation, since it creates nameParams.
But if I use @PathVariable for all parameters, like the following:
@FeignClient(url = "http://localhost:8080")
public interface SpringFeignTestInterface {
@RequestMapping(value = "/upload/{folder}", method = POST)
public ResponseEntity<UploadInfo> upload(@PathVariable("folder") String folder, @PathVariable("file") MultipartFile file, @PathVariable("metadata") UploadMetadata metadata) ;
}
the multipart request is created correctly, since the @PathVariable parameters that aren't actually in the URL, are processed as formParams, see here.
Please note that at the moment I used my own implementation of Feign Encoder to build the multipart request correctly.
Maybe this weird behaviour of @PathVariable should be removed, and @RequestParam should trigger form creation if it contains MultiPartFiles or arrays of them.
It would be great to see that Spring Feign could take full advantage of all REST Controller annotations (not to mention @RequestPart...).
Comment From: cbornet
:+1: for MultipartFile support
Comment From: cbornet
@pcan I tried your PathVariable work-around and couldn't make it work. If I don't set consumes = "multipart/form-data" then I get an error because spring-boot tries to use Jackson to serialize (com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class java.io.ByteArrayInputStream).
If I set the consumes field, then the error is no suitable HttpMessageConverter found for request type [java.util.LinkedHashMap] and content type [multipart/form-data]
which is normal since FormHttpMessageConverter expects a MultiValueMap and not a LinkedHashMap.
I'm testing with Spring-boot 1.3.5.RELEASE and spring-cloud Brixton.SR1
Can you check with the latest versions and tell me if you have a different behavior ?
Comment From: pcan
I haven't tried this yet with the latest release. Are you sure you are using the FeignSpringFormEncoder from my repo? The built-in encoder that ships with feign (JacksonEncoder) has no means to handle multipart requests. However, I'll check it out ASAP.
Comment From: cbornet
No, I'm using the spring-cloud default SpringEncoder. I thought your workaround was working with it.
Comment From: ransikafs
Is this issue still open? I am having the same problem.
Comment From: spencergibb
@ransikafs if the status is open, then it is open. @pcan how about a PR?
Comment From: ulmermark
PathVariable work-around worked for me....if only I found this post earlier in the day.
Comment From: cbornet
Any news ? It's too bad we can't do file upload with spring-cloud...
Comment From: tjuchniewicz
For file upload I use this Feign encoder: https://github.com/OpenFeign/feign-form
Comment From: cbornet
Nice ! It should be included in spring-cloud's encoder !
Comment From: cbornet
Spring-cloud is supported : https://github.com/OpenFeign/feign-form#spring-multipartfile-and-spring-cloud-netflix-feingclient-support !
Comment From: ransika
Hi all,
So excited hear about the solution. I tried things out. But unfortunately, couldn't get it to work yet. So hoping that some folks here can give me a hint to sort things out. The following are the code snippets.
Controller class
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
return dmsFeignClient.handleFileUpload(file);
}
The Feign client is as follows; `@FeignClient(name = "DMS-SERVICE", configuration = DMSFeignClient.MultipartSupportConfig.class) interface DMSFeignClient {
@Configuration
public class MultipartSupportConfig {
@Bean
@Primary
@Scope("prototype")
public Encoder feignFormEncoder() {
return new SpringFormEncoder();
}
}
@RequestMapping(value = "/uploadtest", method = RequestMethod.POST)
public String handleFileUpload(@RequestParam("file") MultipartFile file);
}`
And on the service;
@RequestMapping(value = "/uploadtest", method = RequestMethod.POST)
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
return "success";
}
When I check this out with Postman, I get;
I added headers (multiple/form-data) to all the places, but it didn't work either.
I would be really grateful if someone can give me a pointer to fix this.
Thanks, R
Comment From: tjuchniewicz
I'm not sure if you can pass MultipartFile directly from your controller to service. Try to serialize data in controller and create MultipartFile again before passing to Feign e.g:
MultipartFile file = new MockMultipartFile("test", "test".getBytes());
Any stacktrace?
Comment From: cbornet
Have you tried with File as in the example ?
Comment From: ransikafs
Hi, thanks for the input for both of you. I haven't tried with the "File", it was always Multipart. I will do that and let you know.
Thanks again!
Comment From: cbornet
Also I think you should use @RequestPart instead of @RequestParam
Comment From: cbornet
See https://github.com/OpenFeign/feign-form/blob/master/feign-form-spring/src/test/java/feign/form/feign/spring/IMultipartSupportService.java#L40
Comment From: ransikafs
Hi all,
Thanks to you all, I was able to get it fixed. I am putting the samples so that it will be useful for someone else.
Rest controller end point
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
return uploadFeignClient.handleFileUpload(file);
}
Feign client end point
@RequestMapping(value = "/uploadtest", method = RequestMethod.POST)
public String handleFileUpload(@RequestParam("file") MultipartFile file);
Service end point
@RequestMapping(value = "/uploadtest", method = RequestMethod.POST)
public String handleFileUpload(@RequestParam("file") File file)
Thank you again for the help.
Regards, R
Comment From: cbornet
I tried feign-form-spring and it only deals with part of the issue (encoding of MultipartFile, File and byte[]) but the issue with the parameters annotations not being handled still stands: for instance, you can't have 2 RequestPart, etc...
Also I'm using spring-boot and normally the AllEncompassingFormHttpMessageConverter should be used to encode MultipartFile but it doesn't seem to: I get
Caused by: feign.codec.EncodeException: Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.mock.web.MockMultipartFile] and content type [multipart/form-data]
Comment From: cbornet
Forget my last comment : I forgot that AllEncompassingFormHttpMessageConverter needs a MultiValueMap<String, Object>.
So it's still an issue of transforming a MultipartFile to a form as said in the description.
Comment From: brunnels
I am seeing the same behavior when posting application/x-www-form-urlencoded form data without MultipartFile parameters. I'm only utilizing String parameters. If I annotate them with @RequestParam then the formParams are not populated by contract.parseAndValidatateMetadata called from ReflectiveFeign apply method. If I switch it to @PathVariable then they are. Everything working well after that when using @pcan FeignSpringFormEncoder
Comment From: bilak
Hello,
I've been playing with @RequestPart today. here is my testing application where you can find also branches of spring-cloud-netflix and feign-form and unit test which will show you how it works. It's possible to work with many @RequestPart parameters in one method (one could be for content and another for content metadata(json)).
@spencergibb @xxlabaza please can you take a look how to merge this two project together (of course if that implementation is ok for you)? I think that spring part of feign-form could be moved to spring-cloud-netflix.
Comment From: xxlabaza
@bilak I think you could create pull-requests
Comment From: spencergibb
@bilak a PR would be easier to review than multiple separate repos.
Comment From: spencergibb
Closing this due to inactivity. Please re-open if there's more to discuss.
Comment From: Hronom
Guys the issue is still not solved, by default @RequestPart(value = "file", required = true) MultipartFile file, is not processed by feign auto configuration. Auto configured encoders not support MultipartFile.
To make it work - you need.
1.
Include in your pom.xml dependency:
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.3.0</version>
</dependency>
2. Configure you feign client with next configuration:
@Configuration
public class ServiceClientConfig {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
}
Only after that, you will be able to use @RequestPart(value = "file", required = true) MultipartFile file,.
This should be supported in Spring Boot and Cloud by default.
Please re-open this issue, since it not solved.
From my side I'm not sure that I will be able to produce PR. However I found solution in the example proposed by @bilak solution
I will be very appreciated if someone push PR and make it works by default in Spring Cloud
Comment From: bilak
@Hronom feign-form has one commit which should handle multipart. But I didn't tested it because I'm not working with feign anymore.
Comment From: cbornet
@Hronom Does it work if there are multiple @RequestPart parameters (eg. the file, the filename, etc...)
Comment From: Hronom
Sorry guys for long silence,
@bilak I'm not realy understand what you mean, my point in previous comment, was in that Spring Feign Client AutoConfiguration should include by default support for MultipartFile processing without additional manipulation with dependencies and custom creation of SpringFormEncoder.
@cbornet I have add this code in client interface:
@PostMapping(value = "/process-file-test", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
ResponseEntity<String> processFileTest(
@RequestPart(value = "file", required = true) MultipartFile file,
@RequestPart(value = "file2", required = true) MultipartFile file2
);
and it wont launch and throws error:
Caused by: java.lang.IllegalStateException: Method has too many Body parameters: public abstract org.springframework.http.ResponseEntity com.hronom.FileUploadingServiceClient.processFileTest(org.springframework.web.multipart.MultipartFile,org.springframework.web.multipart.MultipartFile)
however this is not an issue for me.
So my point is that Spring should automatically configure encoder with support of MultipartFile.
As far as I understand this change should be added only here org.springframework.cloud.openfeign.FeignClientsConfiguration or somewhere else?
Comment From: w390888245
@Hronom如果有多个
@RequestPart参数(例如文件,文件名等等),它是否有效
Is there a solution?
Comment From: Hronom
@w390888245 it should be available in 2.0.2.RELEASE, since merge request was accepted here https://github.com/spring-cloud/spring-cloud-openfeign/issues/62
Otherwise the workaround described here https://github.com/spring-cloud/spring-cloud-openfeign/issues/62
Comment From: w390888245
RELEASE thx~
Comment From: sailor4242
Dunno why, but it didn't workout for me (open feign 2.1.0) unless i have set "fileName" in my MultipartFile same as expected @RequestPart name.
Comment From: xxlabaza
@sailor4242, please, provide your code example
Comment From: antemooo
Another issue also with MultiPartFile is here with two alternative solutions.
Comment From: spencergibb
@antemooo please stop commenting the same thing on multiple issues