如何用Express+Nunjucks渲染所有已存在的.njk模板文件?
使用Express+Nunjucks渲染任意.njk模板文件的完整方案
问题背景
我希望用Express+Nunjucks渲染任意已存在的.njk模板文件,但网上找到的示例只有单个路由的写法:
app.get('/', function (req, res) { res.render('index.njk'); });
自己尝试了路由匹配的代码,但缺少文件存在性判断的完整逻辑,需要一个可运行的完整实现方案。
完整实现代码
以下是包含路由匹配、文件存在校验、错误处理的完整代码:
const express = require('express'); const nunjucks = require('nunjucks'); const fs = require('fs').promises; const path = require('path'); const app = express(); const PORT = 3000; // 1. 配置Nunjucks模板环境 const templateDir = path.join(__dirname, 'views'); // 你的模板文件目录,比如项目根目录下的views文件夹 nunjucks.configure(templateDir, { autoescape: true, express: app, watch: true // 开发环境开启模板文件热更新 }); // 2. 处理所有.njk文件的GET请求 app.get(/^\/.+\.njk$/, async (req, res) => { try { // 提取请求中的模板文件名,去掉开头的/ const templateName = req.url.slice(1); // 拼接完整的模板文件路径,防止路径遍历攻击 const templatePath = path.join(templateDir, templateName); // 校验文件是否存在且是合法的.njk文件 await fs.access(templatePath, fs.constants.F_OK); // 确保文件在指定的模板目录内,避免路径遍历漏洞 if (!templatePath.startsWith(templateDir)) { throw new Error('非法路径'); } // 渲染模板 res.render(templateName); } catch (err) { // 文件不存在或路径非法时返回404页面 console.error('模板文件不存在或路径错误:', err.message); res.status(404).render('404.njk'); } }); // 3. 处理根路径请求(可选,比如渲染index.njk) app.get('/', (req, res) => { res.render('index.njk'); }); // 4. 启动服务 app.listen(PORT, () => { console.log(`服务运行在 http://localhost:${PORT}`); });
关键细节说明
- 路由匹配:使用正则表达式
/^\/.+\.njk$/匹配所有以.njk结尾的GET请求,确保只有模板文件请求会进入该路由。 - 文件存在校验:用
fs.promises.access异步检查文件是否存在,避免阻塞事件循环;同时通过path.join和路径前缀校验,防止路径遍历攻击(比如用户请求/../secret.njk这类非法路径)。 - 错误处理:捕获文件不存在、路径非法等异常,返回404状态码并渲染自定义的
404.njk页面。 - 模板目录配置:确保
templateDir指向你实际存放.njk文件的目录,比如项目根目录下的views文件夹。
简化版路由(可选)
如果希望更简洁的路由参数写法,也可以用以下方式,但同样要保留文件存在性校验:
app.get('/:templateName', async (req, res) => { try { const templateName = req.params.templateName; // 确保请求的是.njk文件 if (!templateName.endsWith('.njk')) { return res.status(404).render('404.njk'); } const templatePath = path.join(templateDir, templateName); await fs.access(templatePath, fs.constants.F_OK); if (!templatePath.startsWith(templateDir)) { throw new Error('非法路径'); } res.render(templateName); } catch (err) { res.status(404).render('404.njk'); } });
内容的提问来源于stack exchange,提问作者Sergey L
相关产品推荐
相关产品推荐

