2017-02-11 16 views
8

Jestem po znormalizowanych/kanonicznych URLach dla SPA z serwerem ExpressJS.Standardowe adresy URL ExpressJS/kanoniczne adresy URL:

Mimo że kopia zapasowa SPA jest tworzona przez router po stronie serwera - szablony mogą się nieco różnić w przypadku adresów URL aplikacji. Jedną z różnic jest tag <link rel="canonical" href="https://example.com{{ originalPath }}">. Nie istotne szczegóły, ale wyjaśnia kontekst pytania. Spodziewam się, że będzie tylko jeden adres URL, który odpowiada 200, jego odmiany są przekierowywane do niego za pomocą 301/302 (działa dla żywych ludzi i wyszukiwarek).

Chciałbym, aby adresy URL były rozróżniane i rozróżniane (bez dodatkowych slashów), podobnie jak w przypadku opcji Router, ale niekanoniczne adresy URL (różniące się wielkością liter lub dodatkowym ukośnikiem) powinny powodować przekierowanie 301/302 do kanonicznego adresu URL zamiast 404.

W większości aplikacji po prostu chcę wymusić, aby adresy URL dla tras * były małe (z wyjątkiem zapytań), bez dodatkowych ukośników. To znaczy. app.all('*', ...) oraz przekierowania są:

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

Ale mogą być wyjątki, gdy trasy są określone jednoznacznie. Na przykład, istnieją wielbłądziej obudowane trasy:

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

I wszystkie adresy niekanonicznych powinien zostać przekierowany do kanonicznej (przypadek parametr pozostaje nienaruszona):

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

Logika kanonicznych adresów URL jest dość proste, więc to dziwne, że nie mogłem znaleźć niczego na ten temat odnośnie ExpressJS.

Jaki jest najlepszy sposób na zrobienie tego? Czy istnieje już oprogramowanie pośrednie, które może pomóc?

Odpowiedz

4

Szukałem npms, nie mogłem znaleźć żadnego, więc to podrapało mój umysł i zakodowałem małe zadanie do wykonania dla każdego żądania, które wydaje się działać dobrze. Dodaj to do swojego kodu.

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

ZASTOSOWANIE

Wszystko co musisz zrobić, to dodać swój obiekt urls do urls jak zrobić powyżej nadając jej taką samą wartość klucza. to jest to! Zobacz jakie to proste. Teraz wszystkie żądania Twoich klientów zostaną przekierowane na właściwą stronę z zachowaniem szczególnej ostrożności.

UPDATE

mam również jeden dla POST żądań, myślę, że jest dość dokładna, należy również spróbować. Jeśli chcesz przekierować, gdy użytkownik miksuje ukośniki, musisz napisać dla niego numer regex. Nie miałem czasu, a mój mózg był smażony, więc zrobiłem prosty. Możesz ją zmienić, jak chcesz. Każda struktura sieci ma własny zestaw reguł.

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

Prawdopodobnie chcesz napisać własny middleware za to, coś na wzór tego:

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

Teraz należy pamiętać, że middleware może być umieszczony po wszystkich swoich obecnych trasach , więc jeśli nie pasuje do istniejącej trasy, możesz spróbować sprawdzić, jaka powinna być. Jeśli korzystasz z dopasowywania bez względu na wielkość liter, chcesz to zrobić przed trasami.

+0

Ale co z prośbami spoza GET? A co z trasami wrażliwymi na wielkość liter, jak 'somePath'? Mogą być trasami zamontowanymi, tzn. Segment trasy nie będzie pierwszym po początkowym '/' w url. – estus

+1

spowoduje to pobranie wszystkich typów tras, jednak można wykonać przekierowanie tylko na żądanie GET i zachować całą zawartość. Jeśli chcesz spróbować trochę mądrzejszego dopasowywania (po wstawieniu wielkości liter w linii 1), możesz użyć app._router.stack, aby wyświetlić wszystkie trasy i spróbować znaleźć część wrażliwą na wielkość liter –

0

Stosując ten sam kod jak @ user8377060 tylko z regex zamiast.

// 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

Dzięki za pomysł. Jednak nie widzę powodu, aby używać nowego 'RegExp'. Wymaga ucieczki. Będzie luźno dopasowywał segmenty, nie jest to ogólnie pożądane. Segmenty URL w 'urls' mogą być tworzone jako regexps, jeśli mają być wyrażenia regularne. – estus