Express 不会在虚拟主机中提供静态 ejs 文件

Posted

技术标签:

【中文标题】Express 不会在虚拟主机中提供静态 ejs 文件【英文标题】:Express won't serve static ejs files in vhosts 【发布时间】:2018-07-26 22:01:57 【问题描述】:

我能得到的最接近的是它会让客户端下载它们。它将下载正确的 ejs 文件。

这让我发疯,因为我觉得它应该有效,但它不会。如果我把 html 文件放在那里,它们就可以了。有点乱,因为我一直在尝试各种事情。

var application_root = __dirname;
var express = require('express');
var vhost = require( 'vhost' );
var https = require('https');
var http = require('http');
var fs = require('fs');
var path = require("path");
var forceSSL = require('express-force-ssl');
//do something
var app = express();
var credentials = ;

var config = require('./config.json')[process.env.NODE_ENV || 'dev'];

//Use ejs?
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);

//Ensure all are going to www.
app.all(/.*/, function(req, res, next) 
  var host = req.header("host");
  if (host.match(/^www\..*/i)) 
    next();
   else 
    res.redirect(301, "http://www." + host);
  
);

//Use the virtual hosts
app.use(vhost('*.seq.agency',express.static(path.join(__dirname + '/seq.agency'), 
  extensions: ['ejs'],
  index: 'index.ejs'
)));

app.get('/', function (req, res) 
  res.send('vhosts didn\'t catch this!')
);

var httpServer = http.createServer(app);
if(config.name == "prod")
    /*var options = 
         key: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/privkey.pem'),
         cert: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/fullchain.pem'),
         ca: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/chain.pem')
    */
    console.log('starting on 443');
    //var httpsServer = https.createServer(options, app);
    //httpsServer.listen(443);
    //httpServer.listen(80);
    //app.use(forceSSL);


console.log('['+config.name+'] starting on port',config.port);
httpServer.listen(config.port);

【问题讨论】:

您是否尝试提供 EJS 文件的渲染输出? 你有没有试过这个app.engine('ejs', require('ejs').renderFile);?我相信它会在到达虚拟主机之前将其转换为 .html 文件。 @PatrickRoberts 是的,我基本上只想使用多个使用 <% include('partials/header.ejs'); %> 等的页面 @RickyM 我刚试过。如果我将文件保留为 .html 文件,它只会打印任何 ejs 标签,如果我将其设为 ejs 文件,它不会被 vhosts 捕获 为什么要为ejs 文件添加express.static 【参考方案1】:

问题是您正在考虑渲染静态文件。顾名思义,静态文件是静态的,不需要动态行为和模板渲染

这就是为什么下面的代码不能工作

app.use(vhost('*.seq.agency',express.static(path.join(__dirname + '/seq.agency'), 
  extensions: ['ejs'],
  index: 'index.ejs'
)));

正如您要求它按原样提供文件而不进行处理。因此,我稍微修改了您的代码,以向您展示如何解决此问题的示例

var application_root = __dirname;
var express = require('express');
var vhost = require( 'vhost' );
var https = require('https');
var http = require('http');
var fs = require('fs');
var path = require("path");
var forceSSL = require('express-force-ssl');
//do something
var app = express();
var credentials = ;

var config = require('./config.json')[process.env.NODE_ENV || 'dev'];

//Use ejs?
ejs = require("ejs");
app.set('view engine', 'html');
app.engine('html', ejs.renderFile);
app.engine('ejs', ejs.renderFile);

//Ensure all are going to www.
app.all(/.*/, function(req, res, next) 
    var host = req.header("host");
    if (host.match(/^www\..*/i)) 
        next();
     else 
        res.redirect(301, "http://www." + host);
    
);

//Use the virtual hosts
app.use(vhost('*.seq.agency',function (req, res, next)

    const reqPath = req.path;
    const paths =
        [
            reqPath + ".html",
            reqPath + "index.html",
            reqPath
        ]

    for (file of paths) 
        try 
            let checkPath = path.join(__dirname,"seq.agency", file);
            if (!fs.existsSync(checkPath))
                continue;

            let stat = fs.statSync(checkPath);
            if (stat && stat.isFile())
            
                res.render(checkPath);
                return;
            
         finally 

        
    

    console.log(file);
));

app.get('/', function (req, res) 
    res.send('vhosts didn\'t catch this!')
);

var httpServer = http.createServer(app);
if(config.name == "prod")
    /*var options = 
         key: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/privkey.pem'),
         cert: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/fullchain.pem'),
         ca: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/chain.pem')
    */
    console.log('starting on 443');
    //var httpsServer = https.createServer(options, app);
    //httpsServer.listen(443);
    //httpServer.listen(80);
    //app.use(forceSSL);


console.log('['+config.name+'] starting on port',config.port);
httpServer.listen(config.port);

所以关键是我们按以下顺序检查路径

reqPath + ".html",
reqPath + "index.html",
reqPath

然后,如果它存在,那么我们会在响应中呈现它。这绝不是生产使用代码,因为它允许您进行目录遍历攻击,但这是为了让您了解您做错了什么以及应该如何处理它

【讨论】:

以上是关于Express 不会在虚拟主机中提供静态 ejs 文件的主要内容,如果未能解决你的问题,请参考以下文章

POST 请求不会在 express 中得到处理

尝试通过 express node.js 提供 ejs 文件时出错

11 Express安装入门与模版引擎ejs

Express Js EJS 布局错误:未指定默认引擎且未提供扩展名

Express简单使用

Express简单使用