2017-02-11 110 views
8

我是使用ExpressJS服务器进行SPA标准化/规范化URL的后。ExpressJS路由器标准化/规范URL

虽然它是由服务器端路由器备份的SPA - 模板可能与应用程序URL有所不同。其中一个差异是<link rel="canonical" href="https://example.com{{ originalPath }}">标记。不是相关的细节,但解释了问题的背景。我预计只有一个网址会以200响应,其变体会被重定向到301/302(适用于人类和搜索引擎)。

我想让url大小写敏感和严格(没有额外的斜杠),类似于Router选项,但非规范的url(大小写或额外斜线不同)应该做301/302重定向到规范url而不是404。

在大多数应用程序中,我只是想强制*路径的URL以较小的值(除查询外),没有额外的斜线。即app.all('*', ...)和重定向是:

/Foo/Bar/ -> /foo/bar 
/foo/Bar?Baz -> /foo/bar?Baz 

但也有例外,如果路线明确定义。例如,有骆驼外装路线:

possiblyNestedRouter.route('/somePath')... 
possiblyNestedRouter.route('/anotherPath/:Param')... 

和所有非规范网址应重定向到规范(参数情况下保持完整):

/somepath/ -> /somePath 
/anotherpath/FOO -> /anotherPath/FOO 

规范网址背后的逻辑是很直截了当,所以很奇怪我在ExpressJS这个主题上找不到任何东西。

这样做的最好方法是什么?中间件已经可以提供帮助吗?

回答

4

我已经找了npms,找不到任何,所以这个挠了我的脑海,我已经编写了一个小任务express做每个请求,这似乎工作正常。请将此添加到您的代码中。

var urls = { 
    '/main' : '/main', 
    '/anotherMain' : '/anotherMain' 
} 

app.use(function(req, res, next){ 

    var index = req.url.lastIndexOf('/'); 

    //We are checking to see if there is an extra slash first 
    if(req.url[index+1] == null || req.url[index+1] == undefined || req.url[index+1] == '/'){ 
    //slashes are wrong 
    res.send("please enter a correct url"); 
    res.end(); 
    }else{ 

     for(var item in urls){ 
     if(req.url != item && req.url.toUpperCase() == item.toUpperCase()){ 
      res.redirect(item); 
      console.log("redirected"); 
      //redirected 
     }else if (req.url == item) { 
      console.log("correct url"); 
      next(); 
     }else{ 
      //url doesn't exist 
     } 
    } 

    } 
    next(); 

}); 

app.get('/main', function(req, res){ 
    res.render('mainpage'); 
}); 

app.get('/anotherMain', function(req, res){ 
    res.send("here here"); 
}); 

用法

所有你需要做的是,添加您的网址对象urls像上面给它相同的密钥值来完成。而已。看看它是多么容易。现在您的所有客户请求都将被重定向到正确的页面区分大小写

UPDATE

我也做一个POST请求,我认为这是相当准确的,你也应该给它一个尝试。如果你想在用户混合斜杠时重定向,你需要为它写一些regex。我没有时间,我的大脑被炸,所以我做了一个简单的。无论你喜欢,你都可以改变它。每个网络结构都有自己的一套规则。

var urlsPOST = { 
    '/upload' : '/upload' 
} 

app.use(function(req, res, next){ 

    if(req.method == 'POST'){ 

    var index = req.url.lastIndexOf('/'); 

    if(req.url[index+1] == null || req.url[index+1] == undefined || req.url[index+1] == '/'){ 

     //slashes are wrong 
     res.sendStatus(400); 
     res.end(); 
     return false; 

    }else{ 

     for(var item in urlsPOST){ 
      if(req.url != item && req.url.toUpperCase() == item.toUpperCase()){ 
      res.redirect(307, item); 
      res.end(); 
      return false; 
      //redirected 

      }else if (req.url == item) { 
      console.log("correct url"); 
      next(); 

      }else{ 
      res.sendStatus(404).send("invalid URL"); 
      return false; 
      //url doesn't exist 
      } 
     } 
    } 
    } 
    next(); 
}); 
1

你可能想编写自己的中间件这一点,沿此线的东西:

app.set('case sensitive routing', true); 
 

 
/* all existing routes here */ 
 

 
app.use(function(req, res, next) { 
 
    var url = find_correct_url(req.url); // special urls only 
 
    if(url){ 
 
    res.redirect(url); // redirect to special url 
 
    }else if(req.url.toLowerCase() !=== req.url){ 
 
    res.redirect(req.url.toLowerCase()); // lets try the lower case version 
 
    }else{ 
 
    next(); // url is not special, and is already lower case 
 
    }; 
 
});

现在记住这个中间件可以放在毕竟当前的路线,所以如果它不符合现有的路线,你可以尝试查找它应该是什么。如果你正在使用不区分大小写的路由匹配,你会想要在你的路由之前做到这一点。

+0

但是,非GET请求呢?那么区分大小写的路由如'somePath'呢?它们可以是挂载路线,即路线段不会是在URL中初始'/'后的第一个路段。 – estus

+1

这将获得所有路由类型,但是您只能对GET请求执行重定向并保留所有内容。如果你想尝试做一些更智能的匹配(在第一行插入区分大小写后),你可以使用app._router.stack列出所有的路由,并尝试找到区分大小写的部分 –

0

使用相同的代码@ user8377060 只是一个正则表达式来代替。

// an array of all my urls 
    var urls = [ 
    '/main', 
    '/anotherMain' 
    ] 

    app.use(function(req, res, next){ 

    var index = req.url.lastIndexOf('/'); 

    //We are checking to see if there is an extra slash first 
    if(req.url[index+1] == null || req.url[index+1] == undefined || req.url[index+1] == '/'){ 
    //slashes are wrong 
    res.send("please enter a correct url"); 
    res.end(); 
    }else{ 

     for(var item in urls){ 
     var currentUrl = new RegExp(item, 'i'); 

     if(req.url != item && currentUrl.test(item)){ 
      res.redirect(item); 
      console.log("redirected"); 
      //redirected 
     }else if (req.url == item) { 
      console.log("correct url"); 
      next(); 
     }else{ 
      //url doesn't exist 
     } 
    } 

    } 
    next(); 

    }); 
+1

感谢您的想法。但是,我没有看到使用新的'RegExp'的理由。它需要逃跑。它会松散地匹配段,这通常是不可取的。如果它们应该是regexps,则可以将'urls'中的网址段制作为正则表达式。 – estus