【发布时间】:2018-04-05 00:58:30
【问题描述】:
我正在重构一个需要进行多个 API 调用的 Express 项目。我目前有 9 个单独的函数来进行每个单独的 API 调用,然后在每个 API 调用完成后将其设置为 res.locals。
我创建了一个数组,其中包含我需要访问的所有 API URL,然后我有一个函数可以遍历该数组以进行所有 fetch 调用。但是,我在设置标头时遇到了问题,以便 JSON 数据通过,因为我收到以下消息:
Error: Can't set headers after they are sent.
根据我设置控制器的方式,我可以获取控制器标头和第一个 API 响应以在我的页面上呈现,或者我只获取控制器标头来呈现。鉴于我的情况,我无法找到解决方案,并且想知道是否有人建议纠正这个问题。我已经粘贴了我认为应该足以解决问题的代码,但是如果我可以提供其他任何内容,请告诉我。
API-Helper 文件(进行 API 调用的地方):
function getData(req, res, next) {
for (let i = 0; i < links.length; i ++) {
fetch(links[i])
.then(res => res.json())
.then(fetchRes => {
res.locals.i = fetchRes
next()
})
.catch(err => {
res.json({err})
})
}
}
以下是从第一个 API 调用和标头中获取数据的控制器:
for (let i = 0; i < 10; i ++) {
cryptoController.sendApiData = (req, res) => {
res.json({
message: 'data returned for crypto',
i: res.locals.i
})
}
}
下面是控制器只返回头部时:
for (let i = 0; i < 10; i ++) {
cryptoController.sendApiData = (req, res) => {
res.json({
message: 'data returned for crypto',
i: res.locals[i]
})
}
}
更新以显示更多代码:
完整的控制器:
// import model
const Crypto = require('../models/Crypto')
// initiate controller object
const cryptoController = {}
// find latest cap coin entry
cryptoController.latest = (req, res, next) => {
Crypto.findRecent()
.then(crypto => {
res.json({
message: 'retrieved entry',
data: { crypto }
})
}).catch(next)
}
// send api data
// for (let i = 0; i < 10; i ++) {
cryptoController.sendApiData = (req, res) => {
console.log(res.locals)
res.json({
message: 'data returned for crypto',
i: res.locals.i
})
// }
}
// create new entry
cryptoController.create = (req, res) => {
console.log(req.body, ' req.body from cryptoController#create')
Crypto.create({
// time made
time_made: Date.now(),
// crypto data
usd: req.body.usd,
us_high: req.body.us_high,
us_low: req.body.us_low,
eur: req.body.eur,
eur_high: req.body.eur_high,
eur_low: req.body.eur_low,
trades: req.body.trades,
one_hour: req.body.one_hour,
one_day: req.body.one_day,
seven_days: req.body.Seven_days,
crypto_id: req.body.crypto_id
})
}
module.exports = cryptoController
路线文件:
// import dependencies
const express = require('express')
const cryptoController = require('../controllers/crypto-controller')
const cryptoHelpers = require('../services/crypto-helpers')
// set router variable
const cryptoRouter = express.Router()
// set routes to fetch and store API data
cryptoRouter.post('/crypto', cryptoHelpers.getData, cryptoController.create)
cryptoRouter.get('/crypto', cryptoHelpers.getData, cryptoController.sendApiData)
module.exports = cryptoRouter;
引入路由的服务器文件:
const cryptoRouter = require('./routes/crypto-routes')
app.use('/', cryptoRouter)
模型文件没有被命中,因为此时没有任何东西被插入到数据库中。
【问题讨论】:
-
您将不得不为此控制器代码(整个请求处理程序以及在该请求处理程序中执行的任何代码)显示更多上下文,因为正如您在此处显示的那样,它没有任何意义。您处于
for循环中,将自定义函数分配给cryptoController.sendApiData,但未执行任何操作。另外,将 10 个不同的函数分配给同一个变量也没有什么好处。只有最后一个将被实际分配。另外,您也没有显示任何实际执行cryptoController.sendApiData()的代码。 -
您看到的错误的一般原因是代码针对给定请求发送了多个响应。您只能发送一个响应。例如,对于给定的请求,您只能调用一次
res.json()。第一次调用时,将数据转换为 JSON,发送到客户端并关闭 http 连接。无法发送更多数据。 -
如果我的理解是正确的,我什至无法使用异步函数来做到这一点?
-
异步函数与它没有任何关系。您确实需要向我们展示更多代码并描述您正在尝试为我们做什么,以便更具体地为您提供帮助。
-
明白了。我刚刚更新了我的原始帖子以显示路由和完整的控制器文件,以及如何在 server.js 文件中启动路由。澄清一下:我目前有 9 个 API 调用正在获取它们自己的函数(总共 9 个函数)。我正在尝试重构,以便可以在一个函数中进行所有 API 调用,以减少编写的代码量。非常感谢您的回复,如果我可以发送任何其他信息/说明,请告诉我。