Dowload PDF as a stream of bytes
Asked Answered
D

2

6

I have web API that provides stores files as a stream of bytes. The response is already fetched and saved in the state but now I want to download the file from my react application onClick of a button. I am doing it as follow:

downloadContract( binaryData ) {
        const file = new Blob([binaryData], { type: 'application/pdf' });
        const fileURL = URL.createObjectURL(file);
        window.open(fileURL);
      }

The stream is being fetched correctly after debugging but downloading the file produces an error: Error loading PDF document.

Update:

New endpoint calling using this source:

  callLoadContract: {
    remote( state, id, contractId ) {
      const url = `${base}/vendor/${id}/${contractId }`;
      return $http.instance.api.get( url, id, contractId);
    },
    success: Actions.contractLoaded,
    error: Actions.fail
  }

Handling the response:

  loadContract({id, contractId}) {
    this.getInstance().callLoadContract( id, contractId );
  }

  contractLoaded( response ) {
    if (response && response.data) {
      console.log(response);
      const file = new Blob([response.data], { type: 'application/pdf' });
      const fileURL = URL.createObjectURL(file);
      window.open(fileURL);
    }
  }

Same error.

Depress answered 14/8, 2017 at 10:55 Comment(7)
Which response type is receiving your JS code, arraybuffer or blob ?Suburbanite
Why don't you just serve it from the backend /api/download?fileId=XXXX ?Reproach
The JSON object I am fetching has several documents. They are in blob form I am fetching them all in one GET and then the user should choose which one to view. @CarlosDelgadoDepress
@drinchev multiple files are in the same entityDepress
@user1912404, what you are saying is conceptually wrong, a blob inside a JSON string :v ? Could you explain a little bit more about your problem and if is possible server side code?Suburbanite
@CarlosDelgado the back-end is a java spring boot application. The entity has a list of documents as blob. From my front end, I am parsing the JSON getting the stream of bytes for the selected document.Depress
@drinchev can you please check the update?Depress
S
7

Maybe your problem is nothing related to the way to process the PDF in the client side as your code works pretty well:

import React from 'react';

export default class App extends React.Component {
    constructor(props, context) {
        super(props, context);
    }

    downloadContract() {
        var oReq = new XMLHttpRequest();

        var URLToPDF = "https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf";

        oReq.open("GET", URLToPDF, true);

        oReq.responseType = "blob";

        oReq.onload = function() {
            // Once the file is downloaded, open a new window with the PDF
            // Remember to allow the POP-UPS in your browser
            const file = new Blob([oReq.response], { type: 'application/pdf' });

            const fileURL = URL.createObjectURL(file);

            window.open(fileURL, "_blank");
        };

        oReq.send();
    }

    render() {
        return (
            <div>
                <input type="button" onClick={this.downloadContract} value="Download PDF File"/>
            </div>
        );
    }
}

As expected, the PDF will be downloaded and shown in a new Window of the browser when the user clicks on Download.

However, the easiest approach is the mentioned by @drinchev, just server it in a URL and that's it.

Suburbanite answered 14/8, 2017 at 11:24 Comment(3)
I agree with you, we should call a separate endpoint to fetch the document. Only one concern, can I implement the same idea with a flux architecture?Depress
It worked but without going through altjs. I would live with that.Depress
works for me, but I don't want to route to a new page, just downloadMalia
M
0

Here is my solution for downloading the file but not route to new page:

try {
            let httpClient = new XMLHttpRequest();
            let pdfLink = "http://localhost/";
            httpClient.open('get', pdfLink, true);
            httpClient.responseType = "blob";
            httpClient.onload = function() {
                const file = new Blob([httpClient.response], { type: 'application/pdf' });
                const fileURL = URL.createObjectURL(file);
                const link = document.createElement("a");
                link.href = fileURL;
                link.download = "fileName.pdf";
                link.click();
                // document.body.removeChild(link);
                URL.revokeObjectURL(fileURL);
            };
            httpClient.send();
        } catch (e) {
            console.log(e);
        }
Malia answered 2/6, 2021 at 16:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.