response body from restTemplate is getting truncat

2019-08-18 04:43发布

问题:

I am using spring RestTemplate to download a file. The file size is small. I want to get base64 encoded String. but I see the base64 encoded string is truncated from what it is supposed to be.

Here is my code

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(
                new ByteArrayHttpMessageConverter());


        StreamResourceReader reader = new StreamResourceReader();
        restTemplate.execute(uri, HttpMethod.POST, null,
                new StreamResponseExtractor(reader));
        return reader.getEncodedString();

StreamResourceReader.java

public class StreamResourceReader  {

    private String encodeString;


    public void read(InputStream content) {
        try {
            encodeString = Base64.encodeBase64String(IOUtils.toByteArray(content));
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    public ByteArrayOutputStream getOutputStream(){
        return outputStream;
    }

    public String getEncodedString() {
        return encodeString;
    }
}

StreamResponseExtractor.java

public class StreamResponseExtractor implements ResponseExtractor<InputStream> {

    private StreamResourceReader reader;

    public StreamResponseExtractor(StreamResourceReader resourceReader) {
        this.reader=resourceReader;
    }

    @Override
    public InputStream extractData(ClientHttpResponse response) throws IOException {
        reader.read(response.getBody());
        return null;
   }
}

EDIT just found out that inputStream is truncated. I dont know why and what the fix is. any help here would be appreciated.

Thanks

回答1:

To confirm if your input stream is indeed truncated you can try few things. What IOUtils.toByteArray(content) does is buffers internally the content of input stream and returns the buffer. You can compare the length of buffer array with the byte array the file actually represents. You can do latter with below code

String filePath = "/test.txt";
byte[] fileByteArray= Files.readAllBytes(Paths.get(filePath));

Also ClientHttpResponse ( client view of http response) too has the inputstream available which you can check for content.

InputStream getBody() throws IOException;

As a test for this scenario , I created spring boot Rest client using Rest Template (using the code you shared) and a service for file download again using Spring Boot. On comparing the base encoded String from download vs direct file access, both return same content (compared using String equals method).

UPDATE: Another thing worth trying is just use java.net.HttpURLConnection in a simple program (for help see here) and try to download the content and check whether this works properly because behind all the Spring abstractions, in this case the underlying object used is HttpURLConnection only

SimpleClientHttpResponse extends AbstractClientHttpResponse {

public InputStream getBody() throws IOException {
        InputStream errorStream = this.connection.getErrorStream();
        this.responseStream = (errorStream != null ? errorStream : this.connection.getInputStream());
        return this.responseStream;
    }

...........
...........
}

If this also gives you the same issue, then it's time to look at the server side. May be the server is not sending the complete data.