Node.js多HTTP请求数据整合:如何合并两个接口响应
问题:如何在Express中获取两个API的响应并一同返回?
我有一个API,触发时会发送两个HTTP Get请求,希望获取第一个Get请求的响应并存储到变量中,以便将其与第二个Get请求的响应一同返回。请问实现此需求的最佳方式是什么?
以下是我尝试的代码:
dummy.get("/api/dummy/memberProfileStats", isAuthenticated, (req, res) => { const userId = res.locals.user const memberProfileStatsURL = `/api/reports/users/${userId}/general` const memberLastLoginURL = `/api/users/${userId}/lastlogin` getRequest(memberLastLoginURL) .then(response => { let lastLoginTime = response.data.result }) .catch(errorMessage => { console.log( 'Member Last Login API ERROR: ' + errorMessage) res.json(errorMessage) }); getRequest(memberProfileStatsURL) .then(response => { let stats = response.data.result let pointsRank = [150, 500, 1000, 2000, 3500, 5000, 5500] let totalPoints = stats.totalPoints res.json({ data: { totalPoints: stats.totalPoints, totalPointsRedeemed: stats.totalPointsRedeemed, availablePoints: (stats.totalPoints - stats.totalPointsRedeemed), totalSessionTime: secondsToHm(stats.totalSessionTime), //convert sessionTime seconds to hours loginsCount: stats.totalSessions, rank: rank(totalPoints, pointsRank), createdTime: stats.created, lastLoginTime: lastLoginTime, }, result: response.data.httpStatusCode }) }) .catch(errorMessage => { res.json(errorMessage) }); })
但我遇到了**"lastLoginTime is not defined"**的错误。
解决方案
你碰到的问题根源有两个:
- 变量作用域限制:
lastLoginTime是在第一个then回调的局部作用域里声明的,第二个请求的回调根本访问不到这个变量。 - 异步执行顺序问题:两个
getRequest是并行发起的,第二个请求的回调可能在第一个请求完成前就执行了——就算作用域没问题,lastLoginTime也还没被赋值。
下面给你两种推荐的实现方案:
方案一:用Promise.all并行请求(效率优先)
如果两个API请求之间没有依赖关系,优先用Promise.all同时发起请求,等两者都返回结果后再统一处理,这样能最大化利用时间:
dummy.get("/api/dummy/memberProfileStats", isAuthenticated, async (req, res) => { try { const userId = res.locals.user const memberProfileStatsURL = `/api/reports/users/${userId}/general` const memberLastLoginURL = `/api/users/${userId}/lastlogin` // 同时发起两个请求,等待所有请求完成 const [lastLoginRes, statsRes] = await Promise.all([ getRequest(memberLastLoginURL), getRequest(memberProfileStatsURL) ]) const lastLoginTime = lastLoginRes.data.result const stats = statsRes.data.result const pointsRank = [150, 500, 1000, 2000, 3500, 5000, 5500] const totalPoints = stats.totalPoints res.json({ data: { totalPoints: stats.totalPoints, totalPointsRedeemed: stats.totalPointsRedeemed, availablePoints: stats.totalPoints - stats.totalPointsRedeemed, totalSessionTime: secondsToHm(stats.totalSessionTime), loginsCount: stats.totalSessions, rank: rank(totalPoints, pointsRank), createdTime: stats.created, lastLoginTime: lastLoginTime, }, result: statsRes.data.httpStatusCode }) } catch (error) { console.log('API 请求出错: ' + error) res.json(error) } })
这里用async/await让代码更简洁易读,Promise.all会等待所有请求完成后再继续执行,同时统一处理所有错误,避免了原代码中可能出现的多次调用res.json的问题。
方案二:串行请求(适合有依赖的场景)
如果第二个请求需要依赖第一个请求的结果(虽然你的场景不需要,但可以作为参考),可以按顺序发起请求:
dummy.get("/api/dummy/memberProfileStats", isAuthenticated, (req, res) => { const userId = res.locals.user const memberProfileStatsURL = `/api/reports/users/${userId}/general` const memberLastLoginURL = `/api/users/${userId}/lastlogin` getRequest(memberLastLoginURL) .then(lastLoginRes => { const lastLoginTime = lastLoginRes.data.result // 第一个请求完成后,再发起第二个请求 return getRequest(memberProfileStatsURL).then(statsRes => ({ lastLoginTime, statsRes })) }) .then(({ lastLoginTime, statsRes }) => { const stats = statsRes.data.result const pointsRank = [150, 500, 1000, 2000, 3500, 5000, 5500] const totalPoints = stats.totalPoints res.json({ data: { totalPoints: stats.totalPoints, totalPointsRedeemed: stats.totalPointsRedeemed, availablePoints: stats.totalPoints - stats.totalPointsRedeemed, totalSessionTime: secondsToHm(stats.totalSessionTime), loginsCount: stats.totalSessions, rank: rank(totalPoints, pointsRank), createdTime: stats.created, lastLoginTime: lastLoginTime, }, result: statsRes.data.httpStatusCode }) }) .catch(error => { console.log('API 请求出错: ' + error) res.json(error) }) })
这种方式会先完成第一个请求,拿到lastLoginTime后再发起第二个请求,确保变量已经被正确赋值。
额外提醒
原代码中两个请求的错误处理是分开的,可能会导致重复发送响应(比如两个请求都出错时,会两次调用res.json,引发Express错误)。上面的两种方案都统一了错误处理逻辑,避免了这个问题。
内容的提问来源于stack exchange,提问作者mohamed adel
相关产品推荐
相关产品推荐

