Fastify请求中异步函数未及时返回数据的解决方法
Fastify /pricing接口二次请求返回空数组的异步问题排查与解决
问题概述
在Fastify的/pricing接口中,首次请求能正常渲染数据,但二次请求仅返回空数组。尝试使用async/await但未生效,核心代码如下:
const db = require("playerio-node"); const index = async(fastify, options, done) => { fastify.get("/pricing", async(req, res) => { let items = []; db.PlayerIO.authenticate( "HIDDEN", "HIDDEN", { userId: "Stock", auth: require("../../../../../index").hashGenerator("Stock") }, {}, (client) => { client.bigDB.loadOrCreate("StockItems", "Stock", function (obj) { req.config.stockItems.map(item => { items.push({ name: item.name, img: item.img, price: item.price, stock: obj[item.img] ?? 5 }) }) req.render("/dynamic/pricing/index.liquid", { stockItems: items, Chests: req.config.chests}); }); }, (error) => { console.log(error) } ); return req }); done() }; module.exports = index;
问题原因
- 异步流程未控制:
db.PlayerIO.authenticate和client.bigDB.loadOrCreate都是回调风格的异步API,当前代码没等这些异步操作完成就直接return req,导致Fastify提前结束响应。首次请求可能因巧合(异步回调刚好在响应结束前执行)渲染了数据,但二次请求时异步回调执行滞后,无法正确写入响应。 - 响应返回方式错误:路由函数返回
req不符合Fastify的响应规范,应该用reply对象处理响应。同时req.render在异步回调内调用,无法保证响应被正确处理。 - 错误处理缺失:原代码仅在错误回调中打印日志,未将错误抛出给Fastify处理,问题发生时无法及时定位。
解决方案
把回调风格的PlayerIO API包装成Promise,用async/await严格控制异步流程,同时规范Fastify的响应处理:
const db = require("playerio-node"); const hashGenerator = require("../../../../../index").hashGenerator; const index = async(fastify, options, done) => { // 把PlayerIO authenticate包装成Promise const authenticate = () => { return new Promise((resolve, reject) => { db.PlayerIO.authenticate( "HIDDEN", "HIDDEN", { userId: "Stock", auth: hashGenerator("Stock") }, {}, resolve, // 成功时传递client reject // 失败时传递error ); }); }; // 把bigDB loadOrCreate包装成Promise const loadOrCreateStock = (client) => { return new Promise((resolve, reject) => { client.bigDB.loadOrCreate("StockItems", "Stock", resolve, reject); }); }; fastify.get("/pricing", async(req, reply) => { try { // 等待认证完成 const client = await authenticate(); // 等待数据加载完成 const obj = await loadOrCreateStock(client); // 处理数据 const items = req.config.stockItems.map(item => ({ name: item.name, img: item.img, price: item.price, stock: obj[item.img] ?? 5 })); // 用reply对象渲染并发送响应(根据你的render实现调整) const renderedHtml = await req.render("/dynamic/pricing/index.liquid", { stockItems: items, Chests: req.config.chests }); reply.send(renderedHtml); } catch (error) { // 抛出错误让Fastify处理 reply.code(500).send({ error: error.message }); console.error("Pricing接口错误:", error); } }); done(); }; module.exports = index;
关键优化点
- Promise包装:把所有回调式API转为Promise,确保
async/await能正确等待异步操作完成,避免回调滞后导致的响应异常。 - 响应规范:使用Fastify的
reply对象处理响应,确保只有在数据完全处理完成后才发送响应,避免提前结束请求。 - 错误处理:添加
try/catch捕获所有异步错误,返回500状态码和错误信息,便于问题排查。 - 代码可读性:提前解构引入
hashGenerator,简化代码结构。
内容的提问来源于stack exchange,提问作者Dexter
相关产品推荐
相关产品推荐

