Express中fetch调用API后EJS模板变量未更新问题
问题原因
你遇到的是典型的异步调用时序错误。data()是声明为async的异步函数,内部fetch请求API需要等待网络响应才能更新myStatePopulation变量,但你在POST路由中调用data()后没有等待异步操作执行完成,就立刻执行res.redirect("/")触发GET路由渲染页面。此时页面渲染时API请求还没返回,myStatePopulation还停留在旧值,等控制台打印出正确人口数的时候,页面早就渲染结束了,自然拿不到更新后的值。
另外你把州、年份、人口存在全局变量里的写法也有问题,多用户同时访问站点时,不同用户的查询数据会互相覆盖。
修复方法
不要用全局变量存储单次查询的状态,POST路由中等待API请求返回结果后,再执行页面渲染逻辑,修复后的服务端代码如下:
/* Requiring NPM packages */ const express = require("express"); const ejs = require("ejs"); const fetch = require("node-fetch"); const bodyParser = require("body-parser"); const _ = require("lodash"); /* Using Express */ const app = express(); const port = 3000; /* Using Static Files */ app.use(express.static(__dirname + "/public")); /* Using ejs*/ app.set("view engine", "ejs"); /* Using Body-Parser */ app.use(bodyParser.urlencoded({ extended: true })); /* Fetching API data 直接返回查询结果,不修改全局变量 */ const fetchPopulation = async (nation, year) => { const response = await fetch( "https://datausa.io/api/data?drilldowns=State&measures=Population&year=" + year ); const myJson = await response.json(); const allState = myJson.data; const targetState = allState.find((x) => x.State === nation); // 增加容错,找不到对应州数据时返回提示 return targetState ? targetState.Population : "无匹配数据"; }; /* Starting the server */ app.get("/", function (req, res) { // 首页默认值直接在渲染时传入,无需全局变量存储 res.render("index", { content: "美国人口查询", state: "未选择", year: "未选择", population: "待查询", }); }); /* Posting Data 路由改为async函数,等待API返回后再处理 */ app.post("/", async function (req, res) { try { if (req.body.stateName && req.body.yearDate) { const targetNation = _.capitalize(req.body.stateName); const targetYear = Number(req.body.yearDate); // 等待API请求完成拿到真实人口数据 const population = await fetchPopulation(targetNation, targetYear); // 拿到数据后直接渲染页面,不需要绕路重定向 res.render("index", { content: "美国人口查询", state: targetNation, year: targetYear, population: population, }); } else { console.log("重定向到首页"); res.redirect("/"); } } catch (err) { console.log("数据请求失败: ", err); res.status(500).send("人口数据获取失败,请重试"); } }); app.listen(port, () => console.log("服务运行在端口 : " + port));
原有EJS模板代码不需要修改即可正常使用。
核心改动说明
- 移除了全局存储查询状态的
nation/year/myStatePopulation变量,避免多用户同时访问时数据串扰 - POST路由添加
async声明,调用API时使用await等待请求完成,确保拿到真实人口数据后再渲染页面,从根源解决异步时序问题 - 增加了错误捕获和无匹配数据的容错逻辑,接口请求失败、输入州名不存在时不会直接导致服务崩溃
- 去掉了查询成功后的多余重定向,减少一次不必要的网络请求,页面响应速度更快
内容的提问来源于stack exchange,提问作者Kamran
相关产品推荐
相关产品推荐

