skip to Main Content

In my node Api I use the following function for a specific endpoint in order to create a PDF and return its name:

exports.findOne = (req, res) => {
  .
  .
  .
 const { spawn } = require('child_process');
 const ls = spawn('pdflatex', [name], {cwd: '/path'});

 ls.stdout.on('data', (data) => {
   console.log(`stdout: ${data}`);});

 ls.stderr.on('data', (data) => {
   console.error(`stderr: ${data}`);
 });

 res.status(200).send({ message: name.split('.tex')[0] });
};

This works nice but the name of the PDF is returned before the PDF is created. So I changed the function in order to return the name only after the pdf is created:

exports.findOne = (req, res) => {
  .
  .
  .
 const { spawn } = require('child_process');
 const ls = spawn('pdflatex', [name], {cwd: '/path'});

 ls.stdout.on('data', (data) => {
   console.log(`stdout: ${data}`);});
   res.status(200).send({ message: name.split('.tex')[0] });

 ls.stderr.on('data', (data) => {
   console.error(`stderr: ${data}`);
   res.status(401).send({ message: "PDF Err" });
 });
};

I get the error:

stdout: This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian) (preloaded format=pdflatex)
restricted write18 enabled.

_http_outgoing.js:491
throw new Error('Can't set headers after they are sent.');
^

Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (/.../response.js:771:10)
at ServerResponse.send (/.../response.js:170:12)
at ServerResponse.json (/.../response.js:267:15)
at ServerResponse.send (/.../response.js:158:21)
at Socket.ls.stdout.on (/....report.controller.js:60:18)
at emitOne (events.js:116:13)
at Socket.emit (events.js:211:7)
at addChunk (_stream_readable.js:263:12)
at readableAddChunk (_stream_readable.js:250:11)
at Socket.Readable.push (_stream_readable.js:208:10)
at Pipe.onread (net.js:607:20)

Do you have any ideas how to solve this and to be able to send the answer only after the pdf is created? Thank you!

2

Answers


  1. To send a response after PDF file is generated, you can use the event close in stdout.
    It will be triggered when the spawn command is done.

    ls.stdout.on('close', () => {...});

    Login or Signup to reply.
  2. You can get multiple data events which causes you to try to send the response multiple times which causes the error you see.

    If you want to wait until the spawned process is done, then you should be listening for the close event and sending your response in that.

    exports.findOne = (req, res) => {
      .
      .
      .
     const { spawn } = require('child_process');
     const ls = spawn('pdflatex', [name], {cwd: '/path'});
    
     ls.stdout.on('data', (data) => {
       console.log(`stdout: ${data}`);});
    
     ls.stderr.on('data', (data) => {
       console.error(`stderr: ${data}`);
     });
    
     ls.on('close', (code) => {
       if (!code) {
           res.send({ message: name.split('.tex')[0] });
       } else {
           console.log('error code: ', code);
           res.status(401).send({ message: "PDF Err" });
       }
     }).on('error', (err) => {
        console.log(err);
        res.sendStatus(500);
     });
    
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search