How to modify pipe to return custom response?

2019-02-21 01:30发布

问题:

How can I return a custom response (or error) to the client side with request library? The .pipe() will always pipe the original response back to the client

This returns the original response

request(options)
    .on('error', err => {
      return cb(err);
    })
    .on('response', response => {
      // This is an error
      if (response.statusCode === 500) {
        const error = new Error('File not found');
        return cb(error);
      }
      return cb(null, response, 'application/pdf');
    })
    .pipe(res);

This returns my custom response

request(options)
    .on('error', err => {
      return cb(err);
    })
    .on('response', response => {
      // This is an error
      if (response.statusCode === 500) {
        const error = new Error('File not found');
        return cb(error);
      }
      return cb(null, response, 'application/pdf');
    });
    // .pipe(res);

Is it possible to control whether not to pipe it based on the response?

回答1:

The request will start piping as soon as it receives a response. If you want to control piping or not based on the status code you receive, you'll have to make the pipe call on the response callback like this:

const req = request(options)
  .on('error', err => cb(err))
  .on('response', response => {
    // This is an error
    if (response.statusCode === 500) {
      const error = new Error('File not found');
      return cb(error);
    }

    if (typeof response.end === 'function') {
      req.pipe(response);
    }
    if (response.req.finished) {
      return cb(null, response, 'application/pdf');
    }
  });


回答2:

Once you've read from the stream, that data won't be piped somewhere else, so you can't read the first part of the content, then decide you want to pipe the whole thing and then call .pipe() and expect the original content that you already read to be in the piped response.

You could perhaps read some content, keep track of exactly what you read and then if you decide you just want to pipe it, you could then send what you've already read and the call .pipe(). You'd have to test it yourself to see if there are any race conditions that might cause you to lose some data.

If the data is not large, a relatively easy thing to do would be to read all the data (the request() library can be used in a mode that will just get all the response for you) and then once you have all the data, you could examine the data and decide what to send. You could either send the original data or you could modify it and send the modified data or you could just decide to send something different in its place.