Node.js Express静态资产的区分大小写

时间:2016-04-25 16:17:58

标签: linux node.js macos express case-sensitive

如何设置express.static的路由是否区分大小写?例如Express是否应通过提供名为image.jpeg的本地文件来处理Image.jpeg的请求。

调用express.Router([options])时(如http://expressjs.com/en/4x/api.html所定义)有一个caseSensitive选项,但在调用express.static(root, [options])时,这不是一个选项(同一链接上的文档)。

默认情况下,我会将不区分大小写的卷(/ Mac OS X)中的静态文件提供给区分大小写的卷(/ Linux)。这会导致我们的应用程序出现不一致的错误 - 在Mac OS X下本地不匹配的情况会在本地运行,但在部署到Linux服务器时会失败。

3 个答案:

答案 0 :(得分:1)

我也想要这个,所以我快速找到了404不匹配案件的请求。

效率不高,所以我只在开发中运行它。它只检查文件名。它不会检查文件上方文件夹的大小写。

如何使用它:

var express = require('express');

var app = express();
// You can do this before or after the express() call
// But it must come before express.static() is called
var inDevelopment = (process.NODE_ENV || 'local') === 'local';
if (inDevelopment) {
    require('./modules/makeExpressStaticCaseSensitive')(express);
}

app.use(express.static(path.join(__dirname, 'public_html')));

脚本module/makeExpressStaticCaseSensitive.js

module.exports = function (express) {
    var fs = require('fs')
    var pathlib = require('path');
    var parseUrl = require('express/node_modules/parseurl')

    var oldStatic = express.static;
    var newStatic = function (root, options) {
        var opts = Object.create(options || null);

        var originalHandler = oldStatic(root, options);

        var wrappedHandler = function (req, res, next) {
            var filepath = pathlib.join(root, parseUrl(req).pathname);
            var dirpath = pathlib.dirname(filepath);
            var filename = pathlib.basename(filepath);

            // @todo Reading the entire directory listing and then searching it is quite inefficient for large folders
            //       We should find a more efficient way to do this for one file at a time
            fs.readdir(dirpath, function (err, files) {
                if (err) return next(err);

                var fileIsThere = files.indexOf(filename) >= 0;
                if (fileIsThere) {
                    originalHandler(req, res, next);
                } else {
                    res.status(404).end();
                }
            });
        };

        return wrappedHandler;
    };
    express.static = newStatic;
};

我编写了一个更高效的版本,它将readdir()的输出缓存几秒钟,然后检查整个路径,但它会稍长一些。

答案 1 :(得分:1)

我还获得了一些简单替代解决方案的建议:

  

设置所有静态文件和路径应为小写的策略。

     

通过添加检查文件的构建步骤来强制执行文件策略。

     

如果在路径中找到任何大写字符,则通过添加一些拒绝对静态文件夹的请求的中间件来强制执行请求策略。

答案 2 :(得分:1)

我最近遇到了这个问题,并调试了express.static的基础代码。除了使命名一致之外,我找不到该方案的解决方案。但是我认为最好共享幕后的情况。没有选项可以自定义行为,区分大小写由主机文件系统确定(MacOS APFS默认对我而言区分大小写)。

express.static实际上正在使用npm软件包serve-static,而serve-static使用npm软件包send来返回文件。

发送实际上使用Node.js的fs.stat在返回文件之前检查文件是否存在。该调用是否区分大小写取决于Express.js的主机文件系统。对于区分大小写的主机文件系统,调用将返回并且找不到文件错误。

这是引起问题的代码的一部分

  fs.stat(path, function onstat (err, stat) {
    if (err && err.code === 'ENOENT' && !extname(path) && path[path.length - 1] !== sep) {
      // not found, check extensions
      return next(err)
    }
    if (err) return self.onStatError(err)
    if (stat.isDirectory()) return self.redirect(path)
    self.emit('file', path, stat)
    self.send(path, stat)
  })

我没有找到Express可以传递给它的允许自定义行为的任​​何选项。 express.static还执行许多重要功能,例如为文件设置响应头(缓存等),因此,在没有等效替换的情况下删除它也不是一个好的解决方案。