My controller

@RestController
@RequestMapping("/api")
public class MultiPartController {
    @PutMapping(value = "/upload1", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
    public String upload1(@RequestPart(name = "document") MultipartFile multipartFile) {
        System.out.println(multipartFile.getContentType());
        return "upload1";
    }
    @PutMapping(value = "/upload2", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
    public String upload2(@RequestPart(name = "document") MultipartFile multipartFile,
                          @RequestPart(name = "configuration") String configuration) {
        System.out.println(multipartFile.getContentType());
        System.out.println(configuration);
        return "upload2";
    }
    @PutMapping(value = "/upload3", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.TEXT_PLAIN_VALUE })
    public String upload3(@RequestPart(value = "document") MultipartFile multipartFile,
                          @RequestPart(value = "configuration") DocumentConfiguration configuration) {
        System.out.println(multipartFile.getContentType());
        System.out.println(configuration);
        return "upload3";
    }
}

and the DocumentConfiguration class

@Data
public class DocumentConfiguration {
    private String name;
    private String type;
    private String description;
}

I also have an interceptor

public class MultiPartHttpInterceptor implements HandlerInterceptor {
    Logger logger = Logger.getLogger(this.getClass().getName());
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("===================================================");
        logger.info("Pre Handle http request");
        logger.info(request.getRequestURI());
        AtomicInteger i = new AtomicInteger(1);
        request.getParts().stream()
                .forEach(part -> {
                    logger.info("part "+i + " -> "+part.getName()+"--"+part.getContentType());
                    i.getAndIncrement();
                });
        System.out.println("===================================================");
        return true;
    }
}

Calling directly the controller is working fine.

For /api/aupload1

===================================================
2021-03-10 11:07:17.908  INFO 9152 --- [nio-8090-exec-1] c.e.multipart.MultiPartHttpInterceptor   : Pre Handle http request
2021-03-10 11:07:17.908  INFO 9152 --- [nio-8090-exec-1] c.e.multipart.MultiPartHttpInterceptor   : /api/upload1
2021-03-10 11:07:17.915  INFO 9152 --- [nio-8090-exec-1] c.e.multipart.MultiPartHttpInterceptor   : part 1 -> document--application/pdf
===================================================
application/pdf

For /api/upload2

===================================================
2021-03-10 11:21:40.489  INFO 9152 --- [nio-8090-exec-4] c.e.multipart.MultiPartHttpInterceptor   : Pre Handle http request
2021-03-10 11:21:40.489  INFO 9152 --- [nio-8090-exec-4] c.e.multipart.MultiPartHttpInterceptor   : /api/upload2
2021-03-10 11:21:40.489  INFO 9152 --- [nio-8090-exec-4] c.e.multipart.MultiPartHttpInterceptor   : part 1 -> document--application/pdf
2021-03-10 11:21:40.489  INFO 9152 --- [nio-8090-exec-4] c.e.multipart.MultiPartHttpInterceptor   : part 2 -> configuration--application/json
===================================================
application/pdf
{"name":"test.pdf","type":"pdf","description":"my description"}

For /api/upload3

===================================================
2021-03-10 11:13:11.565  INFO 9152 --- [nio-8090-exec-9] c.e.multipart.MultiPartHttpInterceptor   : Pre Handle http request
2021-03-10 11:13:11.565  INFO 9152 --- [nio-8090-exec-9] c.e.multipart.MultiPartHttpInterceptor   : /api/upload3
2021-03-10 11:13:11.565  INFO 9152 --- [nio-8090-exec-9] c.e.multipart.MultiPartHttpInterceptor   : part 1 -> document--application/pdf
2021-03-10 11:13:11.565  INFO 9152 --- [nio-8090-exec-9] c.e.multipart.MultiPartHttpInterceptor   : part 2 -> configuration--application/json
===================================================
application/pdf
DocumentConfiguration(name=test.pdf, type=pdf, description=my description)

Now my openfeign proxy

@FeignClient(name = "multi-part-client", url = "http://localhost:8090")
public interface MultiPartFeignProxy {

    @PutMapping(value = "/api/upload1", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    String upload1(@RequestPart(name = "document") MultipartFile multipartFile);

    @PutMapping(value = "/api/upload2", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    String upload2(@RequestPart(name = "document") MultipartFile multipartFile,
                   @RequestPart(name = "configuration") String configuration);

    @PutMapping(value = "/api/upload3", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
    String upload3(@RequestPart(name = "document") MultipartFile multipartFile,
                   @RequestPart(name = "configuration") DocumentConfiguration configuration);

}

and the controller used for testing the proxy

@RestController
@RequestMapping("/api")
public class MultiPartClientController {

    MultiPartFeignProxy multiPartFeignProxy;

    public MultiPartClientController(MultiPartFeignProxy multiPartFeignProxy) {
        this.multiPartFeignProxy = multiPartFeignProxy;
    }

    @PutMapping(value = "/upload1-client", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public String upload1(@RequestPart(name = "document") MultipartFile multipartFile) {
        return multiPartFeignProxy.upload1(multipartFile);
    }

    @PutMapping(value = "/upload2-client", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public String upload2(@RequestPart(name = "document") MultipartFile multipartFile,
                          @RequestPart(name = "configuration") String configuration) {
        return multiPartFeignProxy.upload2(multipartFile, configuration);
    }

    @PutMapping(value = "/upload3-client", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public String upload3(@RequestPart(name = "document") MultipartFile multipartFile,
                          @RequestPart(name = "configuration") DocumentConfiguration configuration) {
        return multiPartFeignProxy.upload3(multipartFile, configuration);
    }

}

For /api/upload1-client

===================================================
2021-03-10 11:18:09.275  INFO 9152 --- [nio-8090-exec-1] c.e.multipart.MultiPartHttpInterceptor   : Pre Handle http request
2021-03-10 11:18:09.276  INFO 9152 --- [nio-8090-exec-1] c.e.multipart.MultiPartHttpInterceptor   : /api/upload1
2021-03-10 11:18:09.277  INFO 9152 --- [nio-8090-exec-1] c.e.multipart.MultiPartHttpInterceptor   : part 1 -> document--application/pdf
===================================================
application/pdf

For /api/upload2-client

===================================================
2021-03-10 11:18:43.380  INFO 9152 --- [nio-8090-exec-2] c.e.multipart.MultiPartHttpInterceptor   : Pre Handle http request
2021-03-10 11:18:43.380  INFO 9152 --- [nio-8090-exec-2] c.e.multipart.MultiPartHttpInterceptor   : /api/upload2
2021-03-10 11:18:43.381  INFO 9152 --- [nio-8090-exec-2] c.e.multipart.MultiPartHttpInterceptor   : part 1 -> document--application/pdf
2021-03-10 11:18:43.381  INFO 9152 --- [nio-8090-exec-2] c.e.multipart.MultiPartHttpInterceptor   : part 2 -> configuration--text/plain; charset=UTF-8
===================================================
application/pdf
{"name":"test.pdf","type":"pdf","description":"my description"}

But for /api/upload3-client

2021-03-10 11:19:29.926  WARN 9152 --- [nio-8090-exec-5] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'configuration' is not present]
===================================================
2021-03-10 11:19:29.927  INFO 9152 --- [nio-8090-exec-5] c.e.multipart.MultiPartHttpInterceptor   : Pre Handle http request
2021-03-10 11:19:29.927  INFO 9152 --- [nio-8090-exec-5] c.e.multipart.MultiPartHttpInterceptor   : /api/upload3
2021-03-10 11:19:29.927  INFO 9152 --- [nio-8090-exec-5] c.e.multipart.MultiPartHttpInterceptor   : part 1 -> document--application/pdf
2021-03-10 11:19:29.927  INFO 9152 --- [nio-8090-exec-5] c.e.multipart.MultiPartHttpInterceptor   : part 2 -> name--text/plain; charset=UTF-8
2021-03-10 11:19:29.927  INFO 9152 --- [nio-8090-exec-5] c.e.multipart.MultiPartHttpInterceptor   : part 3 -> description--text/plain; charset=UTF-8
2021-03-10 11:19:29.927  INFO 9152 --- [nio-8090-exec-5] c.e.multipart.MultiPartHttpInterceptor   : part 4 -> type--text/plain; charset=UTF-8
===================================================

All the fields of the DocumentConfiguration class are send as separate parts.

What can I do for having it working ?

I also noticed that for /api/upload2-client the configuration part (part 2) is no more application/json but text/plain; charset=UTF-8. Is it normal or does it come from a mistake in my code ?

Comment From: OlgaMaciaszek

Hi, @tweetysat Thanks for submitting this. Could you please put your example code into a minimal, complete, verifiable example that reproduces the issue and link it here?

Comment From: spring-cloud-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: spring-cloud-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.