【问题标题】:middleware on res.render() when using a lot of routes使用大量路由时 res.render() 上的中间件
【发布时间】:2018-11-10 14:19:57
【问题描述】:

我创建了一个网页以在本地使用它。我有很多如下所示的路线——31 个.ejs 文件和3 个.html 文件。 (它们都在同一个“views”文件夹中)。

//app.js - using node and express
    app.get('/page1', function(req, res){
        res.render('page1');
    });
    app.get('/page2', function(req, res){
        res.sendFile('views/page2.html', { root: __dirname });
    });

我对这些文件中的每一个都使用app.get。我有一种感觉,它不是 DRY 代码,所以现在我正试图找出一种更优雅、更优化的方法来实现相同的结果。

  • 我知道许多 res.sendFile(); 可以替换为单个 express.static() 中间件语句。我通常在一个“公共”文件夹上使用express.static(),我用它来保存我所有的css文件——比如app.use(express.static(path.join(__dirname, 'public')));。但我仍然不明白如何使用它来简化我所有的res.sendFile()

  • 至于许多 res.render(); 路由,我知道如果我不传递任何自定义数据,我可能会用一个处理整个模板文件目录(及其相应路由)的中间件来替换它们) 或文件列表。我只是不知道该怎么做。


非常感谢任何帮助,谢谢!


[更新]
  • 里奇
    • node_modules
    • public
      • css 文件、图片等
    • 观看次数
      • 部分
        • 所有部分文件
      • programmingPublic
        • 来自同一主题的所有 ejs 文件
      • 其他文件(html 和其他 ejs)
    • appjs
    • packagejson
    • package-lockjson



const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');

const app = express(); 

// Body Parser Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

// engine
app.set("view engine", "ejs");

// Set static path
app.use(express.static(path.join(__dirname, 'public')));

const fs = require('fs');

function renderStatic(dir) {
    return function(req, res, next) {
        let target = path.join(dir, req.path);
        fs.access(target, fs.constants.R_OK, function(err) {
            if (err) {
                // file not found, just move on
                next();
            } else {
                res.render(target);
            }
        });
    }
}

app.use(renderStatic(path.join(__dirname, "views/programmingPublic")));

以下是我的侧边菜单的格式:(所有这些文件都在“programmingPublic”文件夹中)

<a href="/programming" class="title">Programming</a>
<li><a href="/c">C</a></li>
<li><a href="/cpp">C++</a></li>
<li><a href="/python">Python</a></li>
<li><a href="/javascript">JavaScript</a></li>
<li><a href="/php">PHP</a></li>

【问题讨论】:

  • 在这个目录层次结构中,__dirname 在哪里?而且,当您的侧菜单中有/javascript 之类的链接时,您希望显示什么文件?而且,它在哪里?
  • 我认为__dirname 是“richie”文件夹,因为它是所有文件和文件夹的根目录。 /javascript 是页面的名称——我在上面保存了有关语言的信息。
  • 所有这些文件(programming、c、cpp、python、javascript、php)都在programmingPublic文件夹中
  • 您是否尝试渲染没有文件扩展名的文件?
  • 它们都是.ejs 文件。我在 app.js 文件上使用了app.set("view engine", "ejs");(就像我上面展示的那样),它总是有效的。

标签: javascript node.js express


【解决方案1】:

如果您有一堆页面需要调用 res.render(),但没有将自定义选项传递给每个渲染,那么您可以将所有这些模板隔离在它们自己的目录中,然后使用如下中间件:

const path = require('path');
const fs = require('fs');

function renderStatic(dir, options) {
    const regex = /^\.|\.\.|\/\.|\\\./;
    options = options || {};

    return function(req, res, next) {
        let target = path.join(dir, req.path);
        if (options.ext && !path.extname(target)) {
           target = target + options.ext;
        }
        // don't allow leading dot or double dot anywhere in the path
        if (regex.test(target)) {
           next();
           return;
        }
        fs.access(target, fs.constants.R_OK, function(err) {
            if (err) {
                // file not found, just move on
                next();
            } else {
                res.render(target);
            }
        });
    }
}

app.use(renderStatic(path.join(__dirname, "renderPublic"), {ext: ".ejs"}));

注意,您必须将这些模板文件隔离在它们自己的目录中,以免在其中找到其他文件。

为了安全完整性,此代码还需要过滤掉路径中的 ... 项,就像 express.static() 所做的那样,以防止攻击者进入您的目录层次结构以访问除目录中的文件之外的其他文件渲染静态目录。


然后,对于您使用res.sendFile() 而没有其他逻辑的路由,只需将这些HTML 文件隔离在它们自己的目录中并将express.static() 指向该目录即可。然后,express.static() 中间件将在该目录中找到匹配的 HTML 文件并自动为您执行res.sendFile(),与处理您的 CSS 文件完全相同。

【讨论】:

  • @richie - 不。不要在 HTML 页面中添加 renderPublic。这仅在服务器本地。这就是您将模板文件放在服务器上的地方 - 与公共 URL 无关。您了解公共 URL(服务器获取请求)和中间件查找匹配文件的目录之间的区别吗?
  • @richie - 使用我回答中的确切代码,您将在__dirname(您的应用程序所在的位置)下创建一个子目录并将模板文件放在那里。但是,您显然可以将它们放在您想要的任何位置,只需将正确的路径传递给renderStatic() 中间件,这样它就知道在哪里寻找匹配项。
  • @richie - 我修改了我的代码,因此您不需要 URL 上的 .ejs
  • @richie - 请注意,我的最新版本还具有安全修复程序,可防止路径在路径中使用诸如 ./ 之类的内容沿层次结构向上移动。
  • @richie - 使用这样的 URL:/../../../app.js。这将能够在您的硬盘上查看renderPublic 目录并获取那些您不希望任何人能够执行的文件。这就是为什么我们在任何路径段中有任何前导点时禁用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-22
  • 2020-06-24
  • 1970-01-01
  • 2014-10-18
  • 2016-06-12
  • 1970-01-01
  • 2019-03-31
相关资源
最近更新 更多