简体   繁体   中英

Send PDF from Server to Client

I'm trying to get access to a pdf from a Google Drive. Whether this access is downloading or viewing, it doesn't really matter, it just needs to be available.

I am using Javascript and NodeJS, with express and google drive api.

I have the following function below which downloads a pdf. But silly me thought this was correct because it worked locally. Then when I deployed it I realised the target filepath no longer makes sense.

function downloadDoc (sourceID, targetName, callback) {
  const dest = fs.createWriteStream(`${os.homedir()}/downloads/`+targetName);
  drive.files.get(
    {sourceID, alt: 'media'},
    {responseType: 'stream'},
    (err, res) => {
      if (err) {
        console.error(err);
      }
      res.data.on('end', () => {
        console.log('Done downloading file.');
        callback();
      })
       .on('error', err => {
          console.error('Error downloading file.');
          throw err;
        })
        .pipe(dest);
    });
}

So what I need to do, is take the data (or response?) from this function and send it over to client side. I assume this is simple to do but, being a simple man, I find myself stuck. I have written this, with the intention that a user can click a link on client side, requesting this URL and calling the function to download the pdf.

app.get('/download_pdf', (req, res) => {
    downloadDoc(documentID, 'docName.pdf', ()=>{ 
      console.log("downloaded pdf");
    });
    res.end();
});

I'm thinking I need to change the argument provided to pipe() since obviously I can't use the filepath.

Similar questions I've checked:
Display Pdf in browser using express js

How to send a pdf file from Node/Express app to the browser

Send pdf via express to js client and download

While these questions are very related to this, I think my issue is due to a lack of understanding of callbacks or requests/responses. I want to learn this properly - not just ask for answers - but as it is, I'm becoming very pressed for time and need a solution soon.

You should be able to simply pipe the returned readable stream to the express res object (which is a writeable stream):

app.get('/download_pdf', (req, res) => {
    drive.files.get({
        fileId: "your-file-id-here",
        alt: 'media'
    })
    .on('end', function () {
        console.log('Done');
    })
    .on('error', function (err) {
        console.log('Error during download', err);
    })
    .pipe(res);    
});

Edit:

as mentioned here , drive.files.get does return a promise. So you need to change it to:

app.get('/download_pdf', (req, res) => {
    drive.files.get({
        fileId,
        alt: 'media'
    }, {
        responseType: 'stream'
    }).then(response => {
        response.data
        .on('end', function () {
            console.log('Done');
        })
        .on('error', function (err) {
            console.log('Error during download', err);
        })
        .pipe(res);
    });
});

So I figured out a way. I'm not sure if this is bad practice but it seems to work. I distinguished between the two response objects by referring to one as response and one as res.

app.get('/download_pdf', (req, res) => {
    const docId = req.query.id;
    drive.files.get({
        fileId: docId,
        alt: 'media'
    }, {
        responseType: 'stream'
    }).then(response => {
        response.data
        .on('end', function () {
            console.log('Done');
        })
        .on('error', function (err) {
            console.log('Error during download', err);
        })
        .pipe(res);
    });

});

Posting this in the event that somebody else has a similar issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM