【问题标题】:ExpressJS router normalized/canonical urlsExpressJS 路由器规范化/规范 url
【发布时间】:2017-06-30 00:33:51
【问题描述】:

我正在寻找带有 ExpressJS 服务器的 SPA 的规范化/规范化 URL。

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

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

在大多数应用程序中,我只想强制 * 路由的 url 小写(查询除外),没有额外的斜杠。 IE。 app.all('*', ...),重定向为:

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

但是,如果明确定义了路由,则可能会有例外。例如,有骆驼套路线:

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

并且所有非规范的url都应该重定向到规范的(参数大小写保持不变):

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

规范 url 背后的逻辑非常简单,所以奇怪的是我在这个主题上找不到任何关于 ExpressJS 的内容。

最好的方法是什么?是否已经有可以提供帮助的中间件?

【问题讨论】:

    标签: javascript node.js express routing


    【解决方案1】:

    我一直在寻找 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 添加到urls 对象,就像上面所做的那样,并为其赋予相同的键值。而已。看看它是多么容易。现在您的所有客户请求都将被重定向到正确的页面区分大小写

    更新

    我也为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();
    });
    

    【讨论】:

      【解决方案2】:

      您可能想为此编写自己的中间件,类似于以下内容:

      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
        };
      });

      现在请记住,这个中间件可以放在所有当前路由之后,这样如果它与现有路由不匹配,您可以尝试查找它应该是什么。如果您使用不区分大小写的路由匹配,您可能希望在路由之前执行此操作。

      【讨论】:

      • 但是非 GET 请求呢?那么像somePath 这样的区分大小写的路由呢?它们可以挂载路由,即路由段不会是 url 中初始 / 之后的第一个。
      • 这将获取所有路由类型,但是您只能对 GET 请求进行重定向并保留所有内容。如果您想尝试做一些更智能的匹配(在第 1 行插入区分大小写之后),您可以使用 app._router.stack 列出所有路由并尝试找到区分大小写的部分
      【解决方案3】:

      使用与@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();
      
        });
      

      【讨论】:

      • 感谢您的想法。但是,我没有理由使用新的RegExp。它需要逃避。它将松散地匹配段,这通常是不可取的。如果urls 中的 URL 段应该是正则表达式,则可以将它们设为正则表达式。
      猜你喜欢
      • 2012-05-22
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-14
      相关资源
      最近更新 更多