NodeJS 在express中全局重定向所有尾随斜杠

js5cn81o  于 2023-02-12  发布在  Node.js
关注(0)|答案(8)|浏览(137)

我正在使用Node.js和Express,并且具有以下路由:

app.get('/', function(req,res){
    locals.date = new Date().toLocaleDateString();

    res.render('home.ejs', locals);
});

function lessonsRouter (req, res, next)
{
    var lesson = req.params.lesson;
    res.render('lessons/' + lesson + '.ejs', locals_lessons);
}

app.get('/lessons/:lesson*', lessonsRouter);

function viewsRouter (req, res, next)
{
    var controllerName = req.params.controllerName;
    res.render(controllerName + '.ejs', locals_lessons);
}
app.get('/:controllerName', viewsRouter);

我的课程页面上有一个Disqus小部件,我注意到一个奇怪的行为,当转到myapp.com/lessonsmyapp.com/lessons/时,我会得到两个不同的页面(其中一个有我之前在Disqus中添加的评论,另一个没有评论)。
有没有一种方法可以使我所有的网址都不带斜杠呢?我试过添加strict routing标志来表示,但是结果是一样的
谢谢

sf6xfgos

sf6xfgos1#

The answer by Tolga Akyüz是令人鼓舞的,但如果斜杠后面有任何字符,则不起作用。例如,http://example.com/api/?q=a被重定向到http://example.com/api而不是http://example.com/api?q=a
下面是一个改进的中间件版本,它通过在重定向目标URL的末尾添加原始查询来解决这个问题。该版本还具有一些安全特性,如更新说明所述。

app.use((req, res, next) => {
  if (req.path.slice(-1) === '/' && req.path.length > 1) {
    const query = req.url.slice(req.path.length)
    const safepath = req.path.slice(0, -1).replace(/\/+/g, '/')
    res.redirect(301, safepath + query)
  } else {
    next()
  }
})

**更新2016:**如jamesk和RFC 1738中所述,只有在域后面没有内容时才能省略尾部斜杠。因此,http://example.com?q=a是无效URL,而http://example.com/?q=a是有效URL。在这种情况下,不应进行重定向。幸运的是,表达式req.path.length > 1解决了这一问题。例如,给定URL http://example.com/?q=a,路径req.path等于/,因此避免了重定向。
**更新2021:**Matt发现,路径开头的双斜杠//会导致危险的重定向。例如,URL http://example.com//evil.example/创建了一个指向//evil.example的重定向,受害者的浏览器会将其解释为http://evil.examplehttps://evil.example。此外,货车Quyet指出,可以有多个尾部斜杠,应妥善处理。由于这些发现,我添加了一行,通过将所有后续斜杠替换为单个/来保护路径。我相信由于the regexp literals are only compiled once,保护措施导致的性能开销可以忽略不计。此外,代码语法已更新为ES6。

sycxhyv7

sycxhyv72#

尝试添加一个中间件;

app.use((req, res, next) => {
  const test = /\?[^]*\//.test(req.url);
  if (req.url.substr(-1) === '/' && req.url.length > 1 && !test)
    res.redirect(301, req.url.slice(0, -1));
  else
    next();
});
pcww981p

pcww981p3#

connect-slashes中间件是专门为这一需求而设计的:https://npmjs.org/package/connect-slashes
安装时:
$ npm install connect-slashes
阅读完整文档:https://github.com/avinoamr/connect-slashes

qcuzuvrc

qcuzuvrc4#

我添加这个答案是因为我对其他解决方案有太多的问题。

/**
 * @param {express.Request} req
 * @param {express.Response} res
 * @param {express.NextFunction} next
 * @return {void}
 */
function checkTrailingSlash(req, res, next) {
  const trailingSlashUrl = req.baseUrl + req.url;
  if (req.originalUrl !== trailingSlashUrl) {
    res.redirect(301, trailingSlashUrl);
  } else {
    next();
  }
}

router.use(checkTrailingSlash);

这将转化为:

/page ==> /page/
/page?query=value ==> /page/?query=value
dwthyt8l

dwthyt8l5#

一个内衬:

router.get('\\S+\/$', function (req, res) {
  return res.redirect(301, req.path.slice(0, -1) + req.url.slice(req.path.length));
});

这将只捕捉需要重定向的网址,并忽略其他。
示例结果:

/         ==> /
/a        ==> /a
/a/       ==> /a
/a/b      ==> /a/b
/a/b/     ==> /a/b
/a/b/?c=d ==> /a/b?c=d
nxowjjhe

nxowjjhe6#

上面的答案在很多情况下都有效,但是GET变量会遇到问题,如果你把它放在另一个express中间件中,它对req.path的依赖会导致问题,它对req.url的依赖也会产生不必要的副作用。

// Redirect non trailing slash to trailing slash
app.use(function(req, res, next){
    // Find the query string
    var qsi = req.originalUrl.indexOf('?');
    // Get the path
    var path = req.originalUrl;
    if(qsi > -1) path = path.substr(0, qsi);
    // Continue if the path is good or it's a static resource
    if(path.substr(-1) === '/' || ~path.indexOf('.')) return next();
    // Save just the query string
    var qs = '';
    if(qsi > -1) qs = req.originalUrl.substr(qsi);
    // Save redirect path
    var redirect = path + '/' + qs;
    // Redirect client
    res.redirect(301, redirect);

    console.log('301 redirected ' + req.originalUrl + ' to ' + redirect);
});

它总是乐于使用GET变量,如果您将其放入中间件中,它也不会中断。

oyt4ldly

oyt4ldly7#

/**
 * @param {express.Request} req
 * @param {express.Response} res
 * @param {express.NextFunction} next
 * @return {void}
 */
function checkTrailingSlash(req, res, next) {
    if (req.path.slice(req.path.length-1) !== '/') {
        res.redirect(301, req.path + '/' + req.url.slice(req.path.length));
    } else {
        next();
    }
}
  
app.use(checkTrailingSlash);

示例结果:

/         ==> /
/a        ==> /a/
/a/       ==> /a/
/a/b      ==> /a/b/
/a/b/     ==> /a/b/
/a/b?c=d  ==> /a/b/?c=d
/a/b/?c=d ==> /a/b/?c=d
cgfeq70w

cgfeq70w8#

如果您使用fastify来处理路线,可以尝试将Fastify的ignoreTrailingSlash选项设置为true。

const fastify = require('fastify')({
  ignoreTrailingSlash: true
})

相关问题