java - PDF is blank and damaged when downloading it from API using JavaScript and React JS - Stack Overflow

I am downloading a pdf file from API, but I am getting a blank PDF. I have tested the API endpoint and

I am downloading a pdf file from API, but I am getting a blank PDF. I have tested the API endpoint and able to get the byte stream on the console and when I save it to File, it got saved and the file looks good. Getting the same response back to the front end using React and I could see the PDF byte stream in the response. However, I could not see the content. It says the file is damaged or corrupted when I opened the downloaded PDF from my local. I have looked at many examples and are following the same pattern, but I think I am missing something here.

My API Java endpoint definition looks like below

@GetMapping(value = "/fetchFile")   
    public ResponseEntity<byte[]> fetchFile(@RequestParam final String key) {
        FileResponse response = myService.readFile(key);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=\"" + key.substring(key.lastIndexOf('/') + 1) + "\"");
        return Mono.just(ResponseEntity.ok().headers(httpHeaders).contentLength(response.getContentLength())
                .contentType(MediaType.parseMediaType(response.getContentType()))
                .body(response.getResponseBytes()));
    }

Frontend:

rounterFetchFile.js

router.get('/', (request, resp) => {
  axios({
    method: 'get',
    baseURL: '',
    responseType: 'blob',
    url: '/fetchFile',
    params: {
      fileKey: 'myfile.pdf'
    }    
  })
    .then(response => {      
      return resp.send(response.data)
    })
    .catch(error => {
      console.error(error)
      return resp.status(error.response.status).end()
    })
})

in myFileComoponent.js
//a function that reads the response from rounterFetchFile.js

const getDocumentOnClick = async () => {
      
        try {
            var {data} = await pullMyPDF()
            var blob = new Blob([data], { type: "application/pdf" });
            var link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);
            link.download = "myFileName.pdf";
            link.click();                     
        } catch (e) {
            console.log(e)
        }
    }

Here

var {data} = await pullMyPDF()

is returning the following content. I pared it with the result returned by the Postman, and it is the same. The generated file size is not empty from the react too. I am not able to find out where is it wrong

Below is the response from API endpoint for the fetchFile

I am downloading a pdf file from API, but I am getting a blank PDF. I have tested the API endpoint and able to get the byte stream on the console and when I save it to File, it got saved and the file looks good. Getting the same response back to the front end using React and I could see the PDF byte stream in the response. However, I could not see the content. It says the file is damaged or corrupted when I opened the downloaded PDF from my local. I have looked at many examples and are following the same pattern, but I think I am missing something here.

My API Java endpoint definition looks like below

@GetMapping(value = "/fetchFile")   
    public ResponseEntity<byte[]> fetchFile(@RequestParam final String key) {
        FileResponse response = myService.readFile(key);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=\"" + key.substring(key.lastIndexOf('/') + 1) + "\"");
        return Mono.just(ResponseEntity.ok().headers(httpHeaders).contentLength(response.getContentLength())
                .contentType(MediaType.parseMediaType(response.getContentType()))
                .body(response.getResponseBytes()));
    }

Frontend:

rounterFetchFile.js

router.get('/', (request, resp) => {
  axios({
    method: 'get',
    baseURL: 'http://mybackend.apibase.url',
    responseType: 'blob',
    url: '/fetchFile',
    params: {
      fileKey: 'myfile.pdf'
    }    
  })
    .then(response => {      
      return resp.send(response.data)
    })
    .catch(error => {
      console.error(error)
      return resp.status(error.response.status).end()
    })
})

in myFileComoponent.js
//a function that reads the response from rounterFetchFile.js

const getDocumentOnClick = async () => {
      
        try {
            var {data} = await pullMyPDF()
            var blob = new Blob([data], { type: "application/pdf" });
            var link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);
            link.download = "myFileName.pdf";
            link.click();                     
        } catch (e) {
            console.log(e)
        }
    }

Here

var {data} = await pullMyPDF()

is returning the following content. I pared it with the result returned by the Postman, and it is the same. The generated file size is not empty from the react too. I am not able to find out where is it wrong

Below is the response from API endpoint for the fetchFile

Share Improve this question edited Sep 28, 2020 at 19:34 mark asked Sep 28, 2020 at 16:34 markmark 4179 silver badges29 bronze badges 8
  • Is there a specific reason you convert the byte stream in React instead of fetching the PDF directly from the back-end (send out application/pdf)? – Fullslack Commented Sep 28, 2020 at 16:42
  • @Fullslack.dev, as per my knowledge, yes the PDF is sending application/pdf from the backend only in my example. The response type is byte[]. I tried with the Resource as response type from the API endpoint, it is still the same issue – mark Commented Sep 28, 2020 at 17:14
  • technicalkeeda./spring-tutorials/… – Fullslack Commented Sep 28, 2020 at 17:26
  • @Fullslack.dev, I checked the response headers, I got the same values what you have referenced in the link. Updated post with the response received in postman from API – mark Commented Sep 28, 2020 at 18:00
  • Again: why is the return type of your ResponseEntity in Java a byte[] and not a InputStream? Then you also convert the byte[] to a blob and pass it around to finally trying to make a PDF out of it. Multiple conversions is bound to cause a error and a corrupted file in the end. Btw I don't consider React a back-end, for me that ends when you leave the Java code in this example. – Fullslack Commented Sep 28, 2020 at 19:24
 |  Show 3 more ments

2 Answers 2

Reset to default 5

I had a similar problem and I fixed it with this:

  • spa

             axios.post(
              'api-url',
              formData,
              {
                responseType: 'blob',
                headers: {
                    'Accept': 'application/pdf'
              }
             })
             .then( response => {
                  const url = URL.createObjectURL(response.data);
                  this.setState({
                      filePath: url,
                      fileType: 'pdf',
                  })
              })
             .catch(function (error) {
                  console.log(error);
             });
    
  • api

     [HttpPost]
     public async Task<IActionResult> Post()
     {
         var request = HttpContext.Request;
    
         var pdfByteArray = await convertToPdfService.ConvertWordStreamToPdfByteArray(request.Form.Files[0], "application/msword");
    
         return File(pdfByteArray, "application/pdf");
     }
    

When the response type is a blob and accepted 'application / pdf' in the header, with that config the job is done ;) ...

Something that worked for me was to send the bytes as base64 from the controller.

API:

public async Task<ActionResult> GetAsync() {
    var documentBytes = await GetDocumentAsync().ConfigureAwait(false);
    return Ok(Convert.ToBase64String(documentBytes))
}

Front End:

client.get(url, {
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    }
})
    .then(response => {
        const link = document.createElement('a');
        link.href = "data:application/octet-stream;base64," + response.data;
        link.download = 'file.pdf';
        link.click();
    })
    .catch(error => {
        console.log(error);
    })

I hope this solves your problem.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744940542a4602295.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信