Express 中间件设置 Header 错误

Express Middleware Setting Header Error

我正在尝试为我的 Express 应用程序实现一个相当简单的中间件功能,它只是向传递给主处理程序的请求 object 添加一个 useCache 值,但出于某种原因,我出现 Can't set headers after they were sent 错误。

const cacheControl = (req, res, next) => {
  if (lastPulled === null) lastPulled = Date().getDay()
  req.useCache = Date().getDay() === lastPulled
  next()
}

app.use(cacheControl)
app.get('/missions', (req, res) => {
  if (req.useCache) res.status(200).json({ result: cache })

  fetch(dumpUrl)
    .then(data => data.text())
    .then(result => {
      cache = result
      res.status(200).json({ result })
    })
    .catch(e => res.status(500).json({ result: e.message }))
})

我读到过,如果错误是由中间件产生的,大部分时间是由于多次 next() 调用,但这不适用于此处,除非我遗漏了一些明显的东西。

当我从应用程序中删除 cacheControl 中间件时,不再有错误,但我无法弄清楚函数中的什么导致错误!任何指点都有帮助!

我猜是因为 res.json() 开火了两次:

app.get('/missions', (req, res) => {
  if (req.useCache) res.status(200).json({ result: cache })

  fetch(dumpUrl)
    .then(data => data.text())
    .then(result => {
      cache = result
      res.status(200).json({ result })
    })
    .catch(e => res.status(500).json({ result: e.message }))
})

// if res.useCase is true, set headers and reply
if (req.useCache) res.status(200).json({ result: cache })

// then fetch and reply again (which generates the error)
fetch(dumpUrl)
    .then(data => data.text())
    .then(result => {
      cache = result
      res.status(200).json({ result })

将其更改为此以利用显式 return

app.get('/missions', (req, res) => {
  if (req.useCache) return res.status(200).json({ result: cache })

  return fetch(dumpUrl)
    .then(data => data.text())
    .then(result => {
      cache = result
      res.status(200).json({ result })
    })
    .catch(e => res.status(500).json({ result: e.message }))
})

错误的性质与您执行此操作时类似:

问题

    function problem() {
        if (true === true) console.log('send problem')
        console.log('send garbage by accident')
    }
    console.log(problem())

解决方案

    function solution() {
        if (true === true) return console.log('send solution')
        return console.log('send nothing')
    }
    console.log(solution())

return 是退出函数的方式。您的问题是您的代码正在检查 if 条件,但随后继续通过它,因为它没有被告知一旦发现该条件就停止。

编写函数的旧方法或不太简洁的方法如下:

app.get('/missions', (req, res) => {
  if (req.useCache) {
    res.status(200).json({ result: cache })
  } else {
    fetch(dumpUrl)
      .then(data => data.text())
      .then(result => {
        cache = result
        res.status(200).json({ result })
      })
      .catch(e => res.status(500).json({ result: e.message }))
  }
})

如果没有 else,它会执行它遇到的每个 if 语句,直到它到达函数的末尾,除非您使用 return 关键字作为退出的提示。

请记住,在 .then() 函数中使用 return 将解析承诺,如果链接了更多 .then(),它不会从上层范围退出。