You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 22:40:25