Reputation: 7837
I have the following Rest resource which downloads a file from DB. It works fine from the browser, however, when I try to do it from a Java client as below, I get 406 (Not accepted error).
...
@RequestMapping(value="/download/{name}", method=RequestMethod.GET,
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public @ResponseBody HttpEntity<byte[]> downloadActivityJar(@PathVariable String name) throws IOException
{
logger.info("downloading : " + name + " ... ");
byte[] file = IOUtils.toByteArray(artifactRepository.downloadJar(name));
HttpHeaders header = new HttpHeaders();
header.set("Content-Disposition", "attachment; filename="+ name + ".jar");
header.setContentLength(file.length);
return new HttpEntity<byte[]>(file, header);
}
...
The client is deployed on the same server with different port (message gives the correct name) :
...
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/activities/download/" + message.getActivity().getName();
File jar = restTemplate.getForObject(url, File.class);
logger.info("File size: " + jar.length() + " Name: " + jar.getName());
...
What am I missing here?
Upvotes: 9
Views: 39163
Reputation: 11
Use this for downloading an JPEG image using exchange. This works perfect.
URI uri = new URI(packing_url.trim());
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.IMAGE_JPEG));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
// Send the request as GET
ResponseEntity<byte[]> result= template.exchange(uri, HttpMethod.GET, entity, byte[].class);
out.write(result.getBody());
Upvotes: 1
Reputation: 17846
The response code is 406 Not Accepted. You need to specify an 'Accept' request header which must match the 'produces' field of your RequestMapping.
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new ByteArrayHttpMessageConverter());
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM));
HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<byte[]> response = restTemplate.exchange(URI, HttpMethod.GET, entity, byte[].class, "1");
if(response.getStatusCode().equals(HttpStatus.OK))
{
FileOutputStream output = new FileOutputStream(new File("filename.jar"));
IOUtils.write(response.getBody(), output);
}
A small warning: don't do this for large files. RestTemplate.exchange(...) always loads the entire response into memory, so you could get OutOfMemory exceptions. To avoid this, do not use Spring RestTemplate, but rather use the Java standard HttpUrlConnection directly or apache http-components.
Upvotes: 25
Reputation: 4074
You may use InputStreamResource with ByteArrayInputStream.
@RestController
public class SomeController {
public ResponseEntity<InputStreamResource> someResource() {
byte[] byteArr = ...;
return ResponseEntity.status(HttpStatus.OK).body(new InputStreamResource(new ByteArrayInputStream(byteArr)));
}
}
Upvotes: 1
Reputation: 23301
maybe try this, change your rest method as such:
public javax.ws.rs.core.Response downloadActivityJar(@PathVariable String name) throws IOException {
byte[] file = IOUtils.toByteArray(artifactRepository.downloadJar(name));
return Response.status(200).entity(file).header("Content-Disposition", "attachment; filename=\"" + name + ".jar\"").build();
}
Also, use something like this to download the file, you are doing it wrong.
org.apache.commons.io.FileUtils.copyURLToFile(new URL("http://localhost:8080/activities/download/" + message.getActivity().getName()), new File("locationOfFile.jar"));
You need to tell it where to save the file, the REST API won't do that for you I don't think.
Upvotes: 3
Reputation: 4432
Try using the execute method on RestTemplate with ResponseExtractor and read the data from stream using extractor.
Upvotes: 0