使用大量路由时,res.render()上的中间件

时间:2018-11-09 22:01:31

标签: javascript node.js express

我创建了一个网页以在本地使用。我有大量的路由,如下所示-31个.ejs文件和3个.html文件。 (它们都在同一个“视图”文件夹中。)

//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();路由,我知道如果不传递任何自定义数据,我可能可以用一个可处理模板文件整个目录(以及它们的相应的路由)或文件列表。我只是不知道该怎么办。


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


[更新]

  
  • richie
    • node_modules
    • 公共
    •         
      • 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>

1 个答案:

答案 0 :(得分: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文件完全相同。