转换 fastify-static 服务文件的响应

Transform response of fastify-static served files

我正在使用 fastify 的 fastify-static 插件,需要转换它提供的文件。例如,我想用“that-link”替换“this-link”。我已经尝试了此处列出的各种 fastify.addHook() 事件,https://www.fastify.io/docs/latest/Hooks/,对我来说明智的是“onSend”,它们在其中演示了 [string].replace(),但都失败了。对于 onSend 处理程序,有效负载不是可变字符串,而是看起来是 PassThrough 可读流。考虑到这一点,我尝试使用 payload.on('data', (chunk) => {...}) 检查数据。那是有见地的。我可以看到文件文本,但我正在深入研究流和 fastify 插件,但不确定如何继续。

  1. 在使用 fastify-static 时,是否有一种简单的方法可以在发送响应之前对其进行转换? (为什么记录的 addHook() 失败了?)
  2. 假设我正确地将负载解释为可读流,我如何在 fastify-static 发送它之前转换它?

端点可以发送字符串、缓冲区或流。

因此 onSend 挂钩将接收其中一种数据类型。

例如:

const fastify = require('fastify')()
const fs = require('fs')
const path = require('path')

fastify.addHook('onSend', async (request, reply, payload) => {
  console.log(`Payload is a ${payload}`);
  return typeof payload
})

fastify.get('/string', (req, reply) => { reply.send('a string') })
fastify.get('/buffer', (req, reply) => { reply.send(Buffer.from('a buffer')) })
fastify.get('/stream', (req, reply) => { reply.send(fs.createReadStream(__filename)) })


fastify.inject('/string', (_, res) => console.log(res.payload))
fastify.inject('/buffer', (_, res) => console.log(res.payload))
fastify.inject('/stream', (_, res) => console.log(res.payload))

fastify-static 将文件作为流发送,因此您需要实现一个转换流。 这里有一个快速而肮脏的例子,假设一个 static/hello 文件存在,内容为:

Hello %name

const { Transform } = require('stream')
const fastify = require('fastify')()
const fs = require('fs')
const path = require('path')

const transformation = new Transform({
  writableObjectMode: false,
  transform(chunk, encoding, done) {
    const str = chunk.toString()
    this.push(str.replace('%name', 'foo bar'))
    done()
  }
})

fastify.addHook('onSend', async (request, reply, payload) => {
  if (typeof payload.pipe === 'function') {
    // check if it is a stream
    return payload.pipe(transformation)
  }
  return payload
})

fastify.register(require('fastify-static'), {
  root: path.join(__dirname, 'static'),
  prefix: '/static/',
})

fastify.inject('/static/hello', (_, res) => console.log(res.payload))

作为建议,我会使用来自 point-of-view 插件的模板系统,因为它支持开箱即用的这些类型的功能。