mark
mark

Reputation: 417

PDF is blank and damaged when downloading it from API using JavaScript and React JS

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 compared 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 enter image description here

Below is the response from API endpoint for the fetchFile enter image description here

enter image description here

Upvotes: 1

Views: 6451

Answers (2)

bcngr
bcngr

Reputation: 845

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.

Upvotes: 0

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 ;) ...

Upvotes: 5

Related Questions