2013-03-11 14 views
13

Sto provando a creare un semplice CMS con express.js che crea dinamicamente percorsi. ottiene un JSON da un database che assomiglia a questo:Il modo migliore per eseguire il routing dinamico con Express.js (node.js)

pagesfromdb = { 
    home = { 
     paths = ['/','/home','/koti'], 
     render = 'home.ejs', 
     fi_FI = {html='<h1>Hei maailma!</h1>'}, 
     en_US = {html='<h1>Hello World!</h1>'} 
    }, 
    about = { 
     paths = ['/about','/tietoja'], 
     render = 'general.ejs', 
     fi_FI = {html='Tietoja'}, 
     en_US = {html='About Us'} 
    } 
} 

e un'iterazione sopra gli oggetti che creano percorsi in questo modo:

Object.keys(pagesfromdb).forEach(function(key) { 
    var page = pagesfromdb[key]; 
    app.get(page.global.paths,function(req, res){ 
     res.render(page.render, page[language]); 
    }); 
}); 

Ora tutto funziona bene. Ma il problema è che ogni volta che un utente modifica il contenuto e i percorsi, è necessario riavviare l'intera app del nodo. Non ho trovato alcuna chiamata API per rimuovere percorsi.

C'è un modo per rimuovere in modo sicuro i vecchi percorsi impostati con app.get? Dovrei farlo anche io?

Esiste un modo migliore per eseguire questo tipo di instradamento? Mi piace questo metodo in quanto mi permette di utilizzare la funzione integrata, è veloce e supporta regex.

Ho provato a rimuovere l'intero app.routes con app.routes = nul ma non ha fatto nulla, le vecchie rotte erano ancora sul posto.

Una cosa che ha effettivamente rimuoverli era

delete app._router.map.get; 
app._router.map.get = []; 

Ma questo in realtà rimuoverli ed è sicuro da usare in modo da non finire dirottamento enormi quantità di RAM se il router mantiene sempre ripopolata?

+2

AFAIk express mantiene tutti i percorsi in app._router.map quindi questo dovrebbe funzionare. – supernova

+0

Ci sono delle cache relative al rendering di cui dovrei preoccuparmi. Oppure vengono semplicemente rimossi con app._router.map poiché sono appena sotto di esso? –

+1

in modalità di visualizzazione delle cache in modalità di produzione, è possibile accedere alla cache tramite app.cache [viewname]. – supernova

risposta

12

Come ha detto @supermova nei commenti, è possibile aggiornare Express al volo. Un'altra architettura da considerare è quella simile ai CMS classici (come Wordpress, ad esempio). In altri CMS, tutte le richieste passano allo stesso 'callback' e su ogni richiesta si cerca nel database quale pagina servire per quell'URL.

app.get('/*', function (req, res) { 
    db.findPage({ slug: req.url}, function (err, pageData) { 
     res.render('page-template', { 
      pageContent: pageData.content, 
      pageTitle: pageData.title 
     }); 
    }); 
}); 

C'è una diminuzione significativa della velocità come risultato di questo metodo, ma alla fine penso che sia più sano. Se la velocità è un problema enorme, è possibile impostare un sistema di memorizzazione nella cache (come Varnish) ma ci saranno grattacapi con l'approccio di modificare i percorsi Express al volo. Ad esempio, cosa succede se devi scalare su due server web? Come fai a tenerli sincronizzati se il server A riceve la richiesta di 'creare una pagina' e quindi sa di aggiornare i suoi percorsi, ma per quanto riguarda il server B? Con ogni richiesta andando al database sarete in grado di scalare orizzontalmente meglio.

+0

Sto già usando Varnish ma IMO non è l'approccio giusto per sistemare le cose ... Questo è in realtà orribilmente lento quando ci sono molte pagine rispetto alla creazione dinamica di percorsi. –

1

Sarebbe molto attento a cercare di creare o distruggere percorsi in fase di esecuzione. Sebbene tu possa modificare tu stesso le strutture di dati, non credo che queste siano documentate come API, quindi rischi di rompersi se/quando aggiorni Express.

Questo potrebbe anche servire come un vincolo di memoria se si crea una nuova rotta per ciascun oggetto di database perché il set di pagine può crescere fino a chissà quanto grande.

Guardalo così ... non vuoi nuovi percorsi; vuoi aggiungere URL alle rotte esistenti. Se si aggiunge un percorso, ciò significa che si desidera che un URL venga mappato su una funzione distinta. Ma stai mappando ogni URL con la stessa funzione. In sostanza, si aggiungono solo le rotte per effetto collaterale. Quello che ti interessa è che un certo insieme dinamico della mappa dell'URL a una funzione specifica.

Potete invece utilizzare un carattere jolly per mappare il modello di URL a una funzione specifica, come

app.get('/pages/*', function(req, res) { 
    var page = pagesfromdb[key]; 
    if (page != null) { 
     res.render(page.render, page.language) 
    } 
    else { 
     res.send(404); 
    } 
}); 

e gestire la mappatura pagesfromdb esterna dello strato di espresso. È possibile utilizzare l'accesso diretto al database, l'accesso alla cache + al database o un aggiornamento basato sul timer, qualunque sia la soluzione migliore per voi.

+0

Il problema con questo metodo è che ho bisogno di ricreare funzionalità regexp. –

+0

Come followup alla mia prima domanda. C'è un modo per riavviare l'applicazione del nodo dentro di sé senza ricorrere a nessun wrapper? –

+0

Può essere fatto, sì, ma non facilmente. Puoi iniziare te stesso usando process.execPath e process.argv [1]. Ma per fare in modo che funzioni, devi prima scollegare tutti i socket di rete e sbloccare tutti i file ... pulizia generale delle risorse. – Brandon

0

L'aggiunta di percorsi può essere eseguita al volo, come indicato. Eliminazione può anche, dato questo fuction:

function deleteRoute(url) { 
    for (var i = app.routes.get.length - 1; i >= 0; i--) { 
    if (app.routes.get[i].path === "/" + url) { 
     app.routes.get.splice(i, 1); 
    } 
    } 
} 

(rubato da Removing a specfic mapped route in Node.js at runtime removes static mapping?)

percorsi Aggiornamento come questo non rendere il vostro app "stateful", e probabilmente portare a un problema se avete bisogno di bilanciamento del carico.