你如何阅读中间件中的流,并且仍然可以在下一个中间件

时间:2018-05-08 14:24:42

标签: node.js express stream middleware

我正在使用代理中间件将多部分数据转发到不同的端点。我想使用以前的中间件从流中获取一些信息,并且仍然可以使用随后的代理中间件的流。是否有流模式允许我这样做?

function preMiddleware(req, res, next) {
  req.rawBody = '';

  req.on('data', function(chunk) {
    req.rawBody += chunk;
  });

  req.on('end', () => {
    next();
  })
}

function proxyMiddleware(req, res, next) {
  console.log(req.rawBody)
  console.log(req.readable) // false
}

app.use('/cfs', preMiddleware, proxyMiddleware)

我希望在将流数据发送到外部端点之前访问name <input name="fee" type='file' />的值。我想我需要这样做,因为端点将fee解析为最终的url,我希望有一个句柄来进行一些后期处理。我愿意接受其他模式来解决这个问题。

2 个答案:

答案 0 :(得分:1)

我认为没有任何机制可以窥视流而不实际永久地从流中删除数据或从流中“取消读取”数据以将其重新放入流中的任何机制。

因此,我可以想到一些可能的想法:

  1. 从流中读取您想要的数据,然后手动将数据发送到最终端点(不使用需要可读流的代理代码)。

  2. 读取流,获取您想要的数据,然后创建一个新的可读流,将您读取的数据放入可读流中,并将该可读流传递给代理。究竟如何传递它只有代理将需要一些查看代理代码。您可能必须创建一个新的git config对象作为新流。

  3. 创建一个流转换,让您在创建可以提供给代理的新流时读取流(甚至可能修改它)。

  4. 注册您自己的req事件处理程序,然后暂停流(注册数据甚至会自动触发流流,您不希望它流动),然后调用{{1} } 马上。我认为,当代理中间件读取流时,这将允许您“查看”所有数据的副本,因为只有多个data事件处理程序,一个用于中间件,一个用于代理中间件。这是一个理论上的想法 - 我还没有尝试过。

答案 1 :(得分:1)

您需要能够在两个不同的方向发送单个流,如果您自己尝试,这并不容易 - 幸运的是我在当天写了一个有用的模块rereadable-stream ,您可以使用,我将使用scramjet来查找您感兴趣的数据。

我假设您的数据将是多部分边界:

const {StringStream} = require('scramjet');
const {ReReadable} = require("rereadable-stream");

// I will use a single middleware, since express does not allow to pass an altered request object to next()
app.use('/cfs', (req, res, next) => {
    const buffered = req.pipe(new ReReadable());        // rewind file to 
    let file = '';                                                  
    buffered.pipe(new StringStream)                     // pipe to a StringStream
        .lines('\n')                                    // split request by line
        .filter(x => x.startsWith('Content-Disposition: form-data;'))
                                                        // find form-data lines
        .parse(x => x.split(/;\s*/).reduce((a, y) => {  // split values
            const z = y.split(/:\s*/);                  // split value name from value
            a[z[0]] = JSON.parse(z[1]);                 // assign to accumulator (values are quoted)
            return a;
        }, {}))
        .until(x => x.name === 'fee' && (file = x.filename, 1))
                                                        // run the stream until filename is found
        .run()
        .then(() => uploadFileToProxy(file, buffered.rewind(), res, next))
                                                        // upload the file using your method

});

您可能需要对此进行一些调整,以使其在真实场景中运行。如果您遇到问题或者在上述答案中有什么问题需要解决,请告诉我。