我正在重构一个Express项目,我需要进行多个API调用。我目前有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)
模型文件没有被点击,因为此时没有任何内容插入到数据库中。
答案 0 :(得分:1)
好的,这里有一个问题:
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})
})
}
}
您正在循环中调用next()
。完成所有操作后,您只能拨打next()
一次。由于看起来这些服务器端fetch()
调用可以并行执行,因此您可以使用Promise.all()
查看它们何时完成。
然后,您还有将数据放入res.locals
的问题。您只是在一个循环中分配相同的res.locals.i
变量,而这个循环并没有真正做任何特别有用的事情。
我认为您必须为数据使用数组,然后在路由链中更改使用res.locals
的代码来访问数组。
function getData(req, res, next) {
let promises = links.map(function(link) {
return fetch(link).then(res => res.json())
});
Promise.all(promises).then(results => {
res.locals.data = results; // res.locals.data is an array of link json
next();
}).catch(err => {
res.status(500).json({err});
});
}
然后,在您的.get()
路由处理程序中,我并不确切知道您为什么要尝试实现的结果类型,但要返回一系列结果,您可以执行以下操作:
cryptoController.sendApiData = (req, res) => {
console.log(res.locals.data)
res.json({
message: 'data returned for crypto',
data: res.locals.data
});
}