3

I am currently trying to send a very long csv file that will be processed in the browser.

I would like to stream it to the client as it would exceed the string size limit and would also take up too much memory in the server.

I have tried

app.get('/test', (req, res)=>{
    let csvStream = byline(fs.createReadStream('./resources/onescsv.csv'));

    csvStream.on('data', (line)=>{
        csvStream.pipe(res);
    });

    csvStream.on('end', () => {
        res.render('./test/test', {
            css:['test/test.css'],
            js:['test/test.js']
        })
    })
});

When I do the above, it sends read stream to the client but it renders to the page which is not what I want. I would like to be able to receive stream buffer by buffer in the client javascript to process the stream as they come in e.g. put them into a table. How can I do this?

forJ
  • 4,309
  • 6
  • 34
  • 60

1 Answers1

4

Well firstly, you don't want to be calling render in the same request your looking to pipe data into the response. You'd want to split these out

  1. Render the page
  2. Start the stream request

To render the page, just have your default route send down the page HTML

app.get('/', (req, res) => {
    res.render('./test/test', {
        css: ['test/test.css'],
        js: ['test/test.js']
    });
});

Then to stream, at the server side tweak your code like

app.get('/api/csv', (req, res) => {
    let stream = fs.createReadStream('./resources/onescsv.csv');
    stream = byline.createStream(stream);
    stream.pipe(res);
    stream.on('end', res.end);
});

Then on your client, in your default HTML page, either on load (or hook up to a button press), fire an AJAX request to pull down the CSV data e.g. using jQuery

$.get('/api/csv', data => {
    // do something with CSV data
});
James
  • 80,725
  • 18
  • 167
  • 237
  • Just one question. when you access data in the jquery call back function does it access the whole variable or chunk by chunk? – forJ Aug 22 '17 at 09:14
  • @serendipity no it doesn't, if that's the desired affect then you'll need to use raw XHR request - [see example](https://stackoverflow.com/a/12280916/82586) – James Aug 22 '17 at 09:17
  • @James nice answer! –  Aug 22 '17 at 09:20
  • I am using exactly same code as your code for the backend and in the front end I did $(document).ready(()=>{$.get('/test/api', data=>{console.log(data)}...` but it says I cant send headers after they are sent – forJ Aug 22 '17 at 09:21
  • when I comment out the api section, it works so something must be wrong with piping... – forJ Aug 22 '17 at 09:22
  • @serendipity see update, change `sendStatus` to just `end` - forgot `sendStatus` would attempt to send headers. – James Aug 22 '17 at 09:26