Mr Smith
Mr Smith

Reputation: 3486

REST service sending corrupted file

I'm trying to create a java REST service that will download a word doc. The file downloads but the contents are just garbage hex, not the actual Word doc contents. My sample code is below. What am I missing? The before & after files have the same amount of bytes.

@SuppressWarnings("resource")
@RequestMapping(value = "get/testdoc", method=RequestMethod.GET, produces="application/octet-stream)
public @ResponseBody ResponseEntity<byte[]>  getTestDoc() throws Throwable{ 

    File doc = new File("C:\\temp\\file.doc");

    InputStream is = new FileInputStream(doc);
    byte[] bytes = IOUtils.toByteArray(is);

    HttpHeaders responseHeaders = new HttpHeaders();  
    responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    responseHeaders.set("Content-Disposition" , "Attachment; filename=file.doc");
    responseHeaders.setContentLength(ProposalDoc.length());



    return new ResponseEntity<byte[]>(bytes, responseHeaders, HttpStatus.OK);
}

Upvotes: 0

Views: 2814

Answers (4)

NHS
NHS

Reputation: 225

Check this code also, it works fine with me.

    @RequestMapping(value = "/get/doc" , method = RequestMethod.GET , 
    produces = "application/msword")
    public ResponseEntity<InputStreamResource> getProposalDocs() throws IOException{
    ClassPathResource docfile = new ClassPathResource("file.doc");
    HttpHeaders headers

 = new HttpHeaders();
    headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
            headers.add("Pragma", "no-cache");
            headers.add("Expires", "0");
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(docfile.contentLength())
                .contentType(MediaType.parseMediaType("application/msword"))
                .body(new InputStreamResource(docfile.getInputStream()));
    }

EDITED: the idea that worked with me to return InputStreamResource instead of byte[]. Also specify the content type as produces="application/octet-stream".

This works fine with me without needed to bypass servlet response..

Upvotes: 0

Mr Smith
Mr Smith

Reputation: 3486

Thanks for all the help. I ended up bypassing Spring & attaching the file to the response, as listed in the code below. I'm suspecting that sprint was converting the bytes somehow behind the scenes. I looked into configuring the ByteArrayHttpMessageConverter, but that didn't seem to help. This is good enough for me, for now.

@SuppressWarnings("resource")
@RequestMapping(value = "get/doc", method=RequestMethod.GET, produces="application/octet-stream")
   public  HttpEntity  getProposalDocs(HttpServletResponse response) throws Throwable{ 
        File doc = new File("C:\\temp\\file.doc");

        InputStream is = new FileInputStream(doc);

        response.setHeader("Content-Disposition", "attachment;filename=\"test.doc\"");
        response.setHeader("Content-Type", "application/octet-stream;");
        StreamUtils.copy(is ,response.getOutputStream());

        return new ResponseEntity(HttpStatus.OK);
    }

Upvotes: 0

Ralph
Ralph

Reputation: 120771

I think there are two problems:

1. The Length Header:

I my opinion there is at least one very strange line:

responseHeaders.setContentLength(ProposalDoc.length());

I think, it should be:

responseHeaders.setContentLength(bytes.length);

2. @ResponseBody Annotation

If you use return type ResponseEntity<byte[]>, then you must NOT add @ResponseBody.

@RequestMapping(value = "get/testdoc", method=RequestMethod.GET)
public ResponseEntity<byte[]>  getTestDoc() throws Throwable{ 
    ...
}

Upvotes: 1

Cosmin Constantinescu
Cosmin Constantinescu

Reputation: 305

try to replace produces="application/octet-stream") with produces="application/vnd.ms-word")

Upvotes: 0

Related Questions