i try to define a feign-client like this:

@FeignClient(value = "epolicy", path = "/epolicy/download", url = "http://10.1.118.45:8001")
public interface EPolicyApi {

    @RequestMapping(method = RequestMethod.POST)
    byte[] download(@RequestParam("policyNo") String policyNo, @RequestParam("idNo") String idNo);
}

my http response's MediaType is application/msdownload。

should i customize a HttpMessageConvter or do some other job?

Comment From: Aloren

Spring converts response into byte array via ByteArrayHttpMessageConverter, but it supports application/octet-stream and / media types, which means all :) So as far as I know, code that you provided should work as is.

Comment From: lexburner

@Aloren you are right,i use 'byte[]' as the return type ,that is ok. but i am not very sure if i want to recevice customize MediaType like application/toString or some uncommonly used MediaType like application/msdownload. is that the best way to use byets[] to recevice as your suggested?

wish your reply to my question,thanks.

Comment From: beldon

I have the same problem. Is there a good solution?

Comment From: beldon

Yes, I do it. Here is my code,including uploading and downloading. I use feign-form to upload file. feign-form

Feign-form maven dependencies

<dependency>
    <groupId>io.github.openfeign.form</groupId>
    <artifactId>feign-form</artifactId>
    <version>2.2.1</version>
</dependency>

<dependency>
    <groupId>io.github.openfeign.form</groupId>
    <artifactId>feign-form-spring</artifactId>
    <version>2.2.1</version>
</dependency>
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;

public class InMemoryMultipartFile implements MultipartFile {

    private final String name;
    private final String originalFileName;
    private final String contentType;
    private final byte[] payload;

    public InMemoryMultipartFile(File file) throws IOException {
        this.originalFileName = file.getName();
        this.payload = FileCopyUtils.copyToByteArray(file);
        this.name = "file";
        this.contentType = "application/octet-stream";
    }

    public InMemoryMultipartFile(String originalFileName, byte[] payload) {
        this.originalFileName = originalFileName;
        this.payload = payload;
        this.name = "file";
        this.contentType = "application/octet-stream";
    }

    public InMemoryMultipartFile(String name, String originalFileName, String contentType, byte[] payload) {
        if (payload == null) {
            throw new IllegalArgumentException("Payload cannot be null.");
        }
        this.name = name;
        this.originalFileName = originalFileName;
        this.contentType = contentType;
        this.payload = payload;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getOriginalFilename() {
        return originalFileName;
    }

    @Override
    public String getContentType() {
        return contentType;
    }

    @Override
    public boolean isEmpty() {
        return payload.length == 0;
    }

    @Override
    public long getSize() {
        return payload.length;
    }

    @Override
    public byte[] getBytes() throws IOException {
        return payload;
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return new ByteArrayInputStream(payload);
    }

    @Override
    public void transferTo(File dest) throws IOException, IllegalStateException {
        new FileOutputStream(dest).write(payload);
    }
}
@FeignClient(value = "material", configuration = MaterialClient.MultipartSupportConfig.class)
public interface MaterialClient {

    @PostMapping("/uploadFile")
    @Headers("Content-Type: multipart/form-data")
    ResponseMO uploadFile(@RequestPart("file") MultipartFile file);


    @GetMapping("/oss/downFile")
    MultipartFile downFile(@RequestParam("key") String key);


    class MultipartSupportConfig {

        @Autowired
        ObjectFactory<HttpMessageConverters> messageConverters;

        @Bean
        @Primary
        @Scope("prototype")
        public Encoder multipartFormEncoder() {
            return new SpringFormEncoder(new SpringEncoder(messageConverters));
        }

        @Bean
        @Primary
        @Scope("prototype")
        public Decoder decoder() {
            Decoder decoder = (response, type) -> {
                if (type instanceof Class && MultipartFile.class.isAssignableFrom((Class) type)) {
                    Collection<String> contentTypes = response.headers().get("content-type");
                    String contentType = "application/octet-stream";
                    if (contentTypes.size() > 0) {
                        String[] temp = new String[contentTypes.size()];
                        contentTypes.toArray(temp);
                        contentType = temp[0];
                    }


                    byte[] bytes = StreamUtils.copyToByteArray(response.body().asInputStream());
                    InMemoryMultipartFile inMemoryMultipartFile = new InMemoryMultipartFile("file","", contentType,bytes);
                    return inMemoryMultipartFile;
                }
                return new SpringDecoder(messageConverters).decode(response, type);
            };
            return new ResponseEntityDecoder(decoder);
        }
    }
}

Comment From: lexburner

@beldon Your rewritten behavior is consistent with my thoughts.But my final practice is to use byte[] as the return value which supported by ByteArrayHttpMessageConverter.Then use the service turns byte[] to file or other type. In my opinion,your inMemoryMultipartFile may be in line with OO design.but MultipartSupportConfig almost will not be reused.:)

Comment From: lexburner

@beldon Your code inspired me , thanks anyway.

Comment From: rainbow702

@beldon

could you please paste your server side code here? I'm wondering how you send the InMemoryMultipartFile to the clint. :handshake:

Comment From: denisgmarques

Yes, I do it. Here is my code,including uploading and downloading. I use feign-form to upload file. [feign-form]

Thank you! It helped me a lot!

Just an improvement, we can get filename from headers using a method like this:

    public static String getFilenameFromHeader(Response resp) {
        String headerName = "content-disposition";

        Map<String, Collection<String>> headers = resp.headers();
        Collection<String> values = headers.get(headerName);
        String value = null;
        if (values != null && values.isEmpty() == false) {
            String[] array = new String[values.size()];
            values.toArray(array);
            value = array[0];
            return value.substring(value.indexOf("filename=") + 10, value.length() - 1);
        }
        return value;
    }

And call it in decoder bean implementation:

    @Bean
    @Primary
    @Scope("prototype")
    public Decoder decoder() {
        Decoder decoder = (response, type) -> {
            if (type instanceof Class && MultipartFile.class.isAssignableFrom((Class) type)) {
                Collection<String> contentTypes = response.headers().get("content-type");
                String contentType = "application/octet-stream";
                if (contentTypes.size() > 0) {
                    String[] temp = new String[contentTypes.size()];
                    contentTypes.toArray(temp);
                    contentType = temp[0];
                }

                byte[] bytes = StreamUtils.copyToByteArray(response.body().asInputStream());
                String filename = FeignUtils.getFilenameFromHeader(response);
                InMemoryMultipartFile inMemoryMultipartFile = new InMemoryMultipartFile(filename, filename, contentType,
                        bytes);
                return inMemoryMultipartFile;
            }
            return new SpringDecoder(messageConverters).decode(response, type);
        };
        return new ResponseEntityDecoder(decoder);
    }