我正在使用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/lessons
和myapp.com/lessons/
时,我会看到两个不同的页面(其中有一个评论)我以前在Disqus中添加了,另一个没有评论。)
有没有办法将所有网址“册封”为没有尾随斜杠?我试图添加strict routing
标志来表达,但结果是相同的
谢谢
答案 0 :(得分:74)
http://example.com/api/?q=a
被重定向到http://example.com/api
而不是http://example.com/api?q=a
。
以下是提议的中间件的改进版本,它通过将原始查询添加到重定向目标网址的末尾来解决问题:
app.use(function(req, res, next) {
if (req.path.substr(-1) == '/' && req.path.length > 1) {
var query = req.url.slice(req.path.length);
res.redirect(301, req.path.slice(0, -1) + query);
} else {
next();
}
});
注意:如jamesk所述并在RFC 1738中说明,只有在域后面没有任何内容时才能省略尾部斜杠。因此,http://example.com?q=a
是无效的网址,其中http://example.com/?q=a
是有效网址。在这种情况下,不应该进行重定向。幸运的是,表达式req.path.length > 1
负责处理。例如,给定网址http://example.com/?q=a
,路径req.path
等于/
,从而避免重定向。
答案 1 :(得分:54)
尝试为此添加中间件;
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();
});
答案 2 :(得分:24)
connect-slashes中间件专为此需求而设计: https://npmjs.org/package/connect-slashes
使用以下命令安装:
$ npm install connect-slashes
答案 3 :(得分:8)
我添加了这个答案,因为我对其他解决方案有太多问题。
router.use(function(req, res, next) {
if (req.originalUrl != req.baseUrl + req.url) {
res.redirect(301, req.baseUrl + req.url);
}
else
next();
});
这将翻译:
/page ==> /page/
/page?query=value ==> /page/?query=value
答案 4 :(得分:3)
一个班轮:
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
答案 5 :(得分:0)
上面的答案会在很多情况下起作用,但是GET变量可能会遇到问题,如果你把它放在另一个快速中间件中,它依赖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变量感到满意,如果你把它放在中间件中,它就不会中断。
答案 6 :(得分:0)
/**
* @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