Fastify升级后EJS渲染MongoDB数据页面白屏无报错解决方法
问题描述
个人网站开发过程中,基于MongoDB的数据库模块已接近完成,升级Fastify相关依赖后,所有传入数据渲染的EJS页面均显示空白,控制台无任何报错输出,无法定位故障点。
当前项目依赖版本:
- fastify: 4.0.3
- path: 0.12.7
- @fastify/view: 7.0.0
- mongodb: 4.7.0
- dotenv: 16.0.1
- ejs: 3.1.8
- @fastify/static: 6.4.0
- @fastify/formbody: 7.0.1
- fastify-plugin: 3.0.1
- mongoose: 6.4.0
原有路由代码:
fastify.get("/result", async function (request, reply) { let search = request.query.search; if (search) { await dbAnime.find({ aliases: search }) .toArray(async function (err, have) { if (!err) { if (have.length > 0) { reply.view("/pages/result.ejs", { results: have }).then(() => { console.log("replied") }); console.log(have); client.close; } else { reply.view("/pages/result.ejs", { results: have }); } } else { reply.code(400) console.error(err); } }); }; });
对应EJS模板代码:
<!DOCTYPE html> <html data-theme=""> <head> <link rel="stylesheet" href="css/style.css"> <link rel="stylesheet" href="css/card.css"> <link rel="preconnect" href="https://fonts.googleapis.com/"> <link rel="preconnect" href="https://cdn.glitch.global/"> <link rel="preconnect" href="https://cdn.discordapp.com/"> <link rel="icon" type="image/png" href=""/> <title><%= results.length %> Résultat</title> </head> <body> <div class="form-container"> <form class="form" action="/result"> <input id="myInput" type="text" class="input" name="search" placeholder="Rechercher un anime..."/> </form> </div> <h2>Résultat: <%= results.length %></h2> <% results.forEach(function(result){%> <div class="paper" id="paper"><img class="poster" src="<%= result.image %>"/> <h1><%= result.title %></h1> <hr/> <p><%= result.synopsis %></p><a class="btn" href="/info?animeName=<%= result.title %>">En savoir plus</a> <div class="space"></div> </div> <% }); %> </body> </html>
故障根因
核心问题是异步写法混用违反Fastify 4的请求处理逻辑,具体问题点:
- MongoDB驱动的
toArray方法如果传入回调函数,就不会返回Promise,前面加的await实际等待的是undefined,外层async路由函数会直接执行结束。Fastify 4对async路由的默认规则是:函数执行完如果没返回内容、也没触发reply.send(),就会直接结束请求,这时候toArray的回调还没执行,等回调里调用reply.view的时候请求已经关闭,所以页面返回空白,也不会抛出常规报错。 - 边界情况没处理:当
search参数不存在时,路由函数没有任何返回逻辑,必然返回空白。 - 代码笔误:
client.close是属性引用,不是方法调用,实际不会执行数据库连接关闭操作。 - 错误分支不完整:数据库查询报错时只设置了400状态码,没有返回任何响应内容。
- 逻辑错误:MongoClient是连接池实例,不应该在单次请求处理完就关闭,否则后续请求会出现数据库连接失败问题,应该在服务整体关闭时统一断开连接。
修复代码
将路由逻辑统一改成async/await写法,不要混用回调,修复后代码如下:
fastify.get("/result", async function (request, reply) { const search = request.query.search; // 处理无搜索参数的情况,避免返回空 if (!search) { return reply.view("/pages/result.ejs", { results: [] }); } try { const have = await dbAnime.find({ aliases: search }).toArray(); console.log(have); // 异步路由直接return reply.view的结果即可,Fastify会自动处理响应发送 return reply.view("/pages/result.ejs", { results: have }); } catch (err) { console.error(err); return reply.code(400).send("数据库查询出错"); } });
额外检查项
如果改完代码还是有问题,确认@fastify/view的注册配置正确,参考配置如下:
const fastify = require('fastify')({ logger: true }); const path = require('path'); fastify.register(require('@fastify/view'), { engine: { ejs: require('ejs') }, root: path.join(__dirname, '你的模板文件存放目录') // 替换为实际的模板目录绝对路径 });
注意:原代码里view路径写的是/pages/result.ejs,要确认这个路径和注册view时配置的root路径拼接后能正确找到模板文件,否则也会出现空白问题。
内容的提问来源于stack exchange,提问作者Normi
相关产品推荐
相关产品推荐

