So, basically the title.
I got 2 microservices. One generates and sends a zip file and the other one receives it, then does some magic, converts it to an array[] of bytes and then sends it somewhere else. But it’s just in theory – I coldn’t make it work.
I need to download a Resource (https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/resources.html) that contains InputStream that my generated zip archive is wrapped into. Writing it inside OutputStream of a HttpServletResponse doesn’t work for me since I can’t use it – later on I need to manipulate the file and this approach is for browser download only (?)
So I did this in the first microservice:
ByteArrayOutputStream baos = new ByteArrayOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(baos); ZipOutputStream zos = new ZipOutputStream(bos); try { zos = service.generateZip(blablabla, zos); baos.close(); bos.close(); zos.close(); } catch (Exception e) { e.printStackTrace(); } ByteArrayResource resource = new ByteArrayResource(baos.toByteArray()); ResponseEntity<Resource> response = ResponseEntity.ok() .contentType(MediaType.parseMediaType("application/zip;charset=UTF-8")) .contentLength(resource.contentLength()) .header(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.parse(format("attachment; filename="doc_%s.zip"", id)).toString()) .body(resource);
And this in second:
public byte[] getZip(DocRequest request) throws IOException { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType("application/zip;charset=UTF-8")); headers.setAccept(Collections.singletonList(MediaType.parseMediaType("application/zip;charset=UTF-8"))); // headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); // headers.setAccept(Collections.singletonList(MediaType.APPLICATION_OCTET_STREAM)); Resource response = restTemplate.exchange( apiUrl + "/doc/get-zip/" + request.getId(), HttpMethod.GET, new HttpEntity<>(null, headers), Resource.class) .getBody(); return (response != null) ? IOUtils.toByteArray(response.getInputStream()) : null; }
also added ResourceHttpMessageConverter to a restTemplate to configs of both microservices:
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL)); converter.setObjectMapper(objectMapper); ResourceHttpMessageConverter resourceConverter = new ResourceHttpMessageConverter(); resourceConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL)); return builder.interceptors(...) .messageConverters(resourceConverter, converter) .configure(restTemplate);
Without them I get an error which looks like this:
{"method":"POST","exceptionName":"RestClientException","detail":"Error while extracting response for type [interface org.springframework.core.io.Resource] and content type [application/octet-stream]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Invalid UTF-8 middle byte 0x59; nested exception is com.fasterxml.jackson.core.JsonParseException: Invalid UTF-8 middle byte 0x59n at [Source: (ByteArrayInputStream); line: 1, column: 13]"}
or
{"method":"POST","exceptionName":"RestClientException","detail":"Error while extracting response for type [interface org.springframework.core.io.Resource] and content type [application/zip;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Invalid UTF-8 start byte 0x91; nested exception is com.fasterxml.jackson.core.JsonParseException: Invalid UTF-8 start byte 0x91n at [Source: (ByteArrayInputStream); line: 1, column: 12]"}
depending on contentType (application/octet-stream and application/zip (application/zip;charset=UTF-8) respectively).
After I added ResourceHttpMessageConverter it now gives me
{"method":"POST","exceptionName":"RestClientException","detail":"Error while extracting response for type [interface org.springframework.core.io.Resource] and content type [application/octet-stream]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unrecognized token 'PKu0003..': was expecting ('true', 'false' or 'null'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'PKu0003...': was expecting ('true', 'false' or 'null')n at [Source: (ByteArrayInputStream); line: 1, column: 28]"}
Maybe I am using something wrong? Any advice would be appreciated. Thank you in advance
Advertisement
Answer
Ended up encoding byte array to base64 string then sent it as
return ResponseEntity.ok().body(Base64Utils.encodeToString(baos.toByteArray()));
Then in my receiving microservice I added the following to my restTemplate config:
// idk if it's need to put StringHttpMessageConverter first in the list, but I did it just in case List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(); messageConverters.add(new StringHttpMessageConverter()); messageConverters.add(new MappingJackson2HttpMessageConverter()); restTemplate.setMessageConverters(messageConverters);
And it worked!
Don’t know if it’s right, but maybe someone will find it helpful