Come reindirizzare in expressjs mentre passo un po 'di contesto?


270

Sto usando express per creare un'app Web in node.js. Questa è una semplificazione di ciò che ho:

var express = require('express');
var jade = require('jade');
var http = require("http");


var app = express();
var server = http.createServer(app);

app.get('/', function(req, res) {
    // Prepare the context
    res.render('home.jade', context);
});

app.post('/category', function(req, res) {
    // Process the data received in req.body
    res.redirect('/');
});

Il mio problema è il seguente:

Se trovo che i dati inviati /categorynon vengono convalidati, vorrei passare un ulteriore contesto alla /pagina. Come potrei farlo? Il reindirizzamento non sembra consentire alcun tipo di parametro aggiuntivo.


1

La terminologia conta qui: non esiste una /pagina. Esiste un /percorso che Express Can Service offre e un modello di homepage che Express può eseguire il rendering. Se desideri conservare alcuni dati per il rendering del modello di homepage dopo un reindirizzamento, nonostante la risposta accettata, le sessioni sono tuoi amici. Ti danno un archivio dati che persiste tra le richieste e le risposte per i singoli utenti di navigazione in modo da poter inserire i dati durante la /categorygestione e quindi estrarli se presenti durante la /consegna.
Mike 'Pomax' Kamermans,

Risposte:


368

Esistono alcuni modi per passare i dati a percorsi diversi. La risposta più corretta è, ovviamente, stringhe di query. È necessario garantire che i valori siano correttamente encodeURIComponent e decodeURIComponent .

app.get('/category', function(req, res) {
  var string = encodeURIComponent('something that would break');
  res.redirect('/?valid=' + string);
});

Puoi afferrarlo nell'altro percorso ottenendo i parametri inviati utilizzando req.query.

app.get('/', function(req, res) {
  var passedVariable = req.query.valid;
  // Do something with variable
});

Per un modo più dinamico puoi utilizzare il urlmodulo principale per generare la stringa di query per te:

const url = require('url');    
app.get('/category', function(req, res) {
    res.redirect(url.format({
       pathname:"/",
       query: {
          "a": 1,
          "b": 2,
          "valid":"your string here"
        }
     }));
 });

Quindi, se vuoi reindirizzare tutte le variabili della stringa di query req, puoi semplicemente farlo

res.redirect(url.format({
       pathname:"/",
       query:req.query,
     });
 });

E se stai usando Nodo> = 7.x puoi anche usare il querystringmodulo principale

const querystring = require('querystring');    
app.get('/category', function(req, res) {
      const query = querystring.stringify({
          "a": 1,
          "b": 2,
          "valid":"your string here"
      });
      res.redirect('/?' + query);
 });

Un altro modo per farlo è impostare qualcosa nella sessione. Puoi leggere come impostarlo qui , ma impostare e accedere alle variabili è qualcosa del genere:

app.get('/category', function(req, res) {
  req.session.valid = true;
  res.redirect('/');
});

E più tardi dopo il reindirizzamento ...

app.get('/', function(req, res) {
  var passedVariable = req.session.valid;
  req.session.valid = null; // resets session variable
  // Do something
});

C'è anche la possibilità di utilizzare una vecchia caratteristica di Express, req.flash. Per farlo nelle versioni più recenti di Express è necessario utilizzare un'altra libreria. Fondamentalmente ti consente di impostare variabili che verranno visualizzate e reimpostate al successivo accesso a una pagina. È utile per mostrare errori agli utenti, ma di nuovo è stato rimosso per impostazione predefinita. MODIFICARE: trovata una libreria che aggiunge questa funzionalità.

Spero che questo ti dia un'idea generale di come trasferire informazioni in un'applicazione Express.


6
Querys non si sente davvero bene a passare il contesto, in quanto potrebbe essere grande come un lungo paragrafo o anche di più. Per quanto riguarda le sessioni, potrebbe funzionare. ma non sembra proprio giusto, dato che questo non sembra lo scopo giusto delle sessioni ...
Tenda Enrique Moreno,

@Dbugger Oops, non avevo capito che avevi posto la domanda. Se sei preoccupato di passare troppe informazioni all'utente tramite querystring, potrebbe essere meglio archiviare i dati di convalida in un DB e quindi interrogarli quando raggiungi la /strada principale . Un'altra opzione è quella di chiamare il percorso postale tramite AJAX e archiviare i dati risultanti nell'archivio locale o qualcosa di simile.
AlbertEngelB,

13
Buona risposta, ma penso che le sessioni siano l'approccio migliore rispetto alle stringhe di query: non esporre elementi negli URL!
user2562923

2
@ user2562923 Sono d'accordo, le sessioni o i POST sono migliori dei GET per passare il contesto. La risposta è stata piuttosto vaga, quindi non ero sicuro di che tipo di informazioni stesse passando il richiedente.
AlbertEngelB,

Il nodo js ha 2 moduli principali che generano la stringa di query
Fareed Alnamrouti,

42

Il modo più semplice che ho trovato per passare i dati tra routeHandlers next()non è necessario utilizzare il reindirizzamento o le sessioni. Opzionalmente potresti semplicemente chiamare il tuo homeCtrl(req,res)anziché next()e semplicemente passare il reqeres

var express  = require('express');
var jade     = require('jade');
var http     = require("http");


var app    = express();
var server = http.createServer(app);

/////////////
// Routing //
/////////////

// Move route middleware into named
// functions
function homeCtrl(req, res) {

    // Prepare the context
    var context = req.dataProcessed;
    res.render('home.jade', context);
}

function categoryCtrl(req, res, next) {

    // Process the data received in req.body
    // instead of res.redirect('/');
    req.dataProcessed = somethingYouDid;
    return next();
    // optionally - Same effect
    // accept no need to define homeCtrl
    // as the last piece of middleware
    // return homeCtrl(req, res, next);
}

app.get('/', homeCtrl);

app.post('/category', categoryCtrl, homeCtrl);

4
Amico, adoro questa risposta. Mi ha aiutato a uscire da un buco lì - anche se ho davvero bisogno di fare di più mentre il mio istinto mi chiedeva di passare req e res in come argomenti per next ().
JonRed,

1
Risposta molto buona e conservatrice! Molto più facile e molto più sicuro delle altre risposte.
Triforcey,

2
Questo approccio sembra essere più pulito, ma non sono sicuro se lascerà la barra degli indirizzi nell'ultimo percorso o se finirà alle/
Danielo515,

1
@ Danielo515 purtroppo finirà a / categorie, quindi in realtà è lo stesso del semplice rendering della vista direttamente in / categorie ...
Manuel Graf

2
Non sono d'accordo che stai solo usando il router come servizio per rendere la vista differita che lascerà l'URL così com'è, è una cattiva idea strutturare il tuo codice in questo modo, lo scopo del prossimo è passare al middleware successivo e di solito isolare la nostra logica aziendale dalla logica dei router
Fareed Alnamrouti,

9

Ho dovuto trovare un'altra soluzione perché nessuna delle soluzioni fornite ha effettivamente soddisfatto i miei requisiti, per i seguenti motivi:

  • Stringhe di query : potresti non voler utilizzare le stringhe di query perché gli URL potrebbero essere condivisi dai tuoi utenti e, a volte, i parametri della query non hanno senso per un altro utente. Ad esempio, un errore come ?error=sessionExpirednon dovrebbe mai essere visualizzato per caso a un altro utente.

  • req.session : potrebbe non essere necessario utilizzarlo req.sessionperché è necessaria la dipendenza dalla sessione espressa per questo, che include la configurazione di un archivio di sessioni (come MongoDB), che potrebbe non essere necessario, o che forse si sta già utilizzando soluzione store di sessione.

  • next () : potresti non voler utilizzare next()o next("router")perché questo essenzialmente rende la tua nuova pagina sotto l'URL originale, non è in realtà un reindirizzamento al nuovo URL, più simile a un forward / rewrite, che potrebbe non essere accettabile.

Quindi questa è la mia quarta soluzione che non soffre di nessuno dei precedenti problemi. Fondamentalmente comporta l'uso di un cookie temporaneo, per il quale dovrai prima installare cookie-parser . Ovviamente questo significa che funzionerà solo dove i cookie sono abilitati e con una quantità limitata di dati.

Esempio di implementazione:

var cookieParser = require("cookie-parser");

app.use(cookieParser());

app.get("/", function(req, res) {
    var context = req.cookies["context"];
    res.clearCookie("context", { httpOnly: true });
    res.render("home.jade", context); // Here context is just a string, you will have to provide a valid context for your template engine
});

app.post("/category", function(req, res) {
    res.cookie("context", "myContext", { httpOnly: true });
    res.redirect("/");
}

Non è richiesto alcun archivio sessioni express-session. Un database rende le sessioni persistenti al riavvio del server.
Mike 'Pomax' Kamermans,

6

usa app.set e app.get

Impostazione dei dati

router.get(
  "/facebook/callback",
  passport.authenticate("facebook"),
  (req, res) => {
    req.app.set('user', res.req.user)
    return res.redirect("/sign");
  }
);

Ottenere dati

router.get("/sign", (req, res) => {
  console.log('sign', req.app.get('user'))
});

2
cattiva idea per implementarlo. può interessare tutto l'utente req.app è uguale per tutti gli utenti. possiamo usare express-session invece di questo.
ujjal das

5

Ecco cosa ti suggerisco senza usare altre dipendenze, solo nodo ed espresso, usa app.locals, ecco un esempio:

    app.get("/", function(req, res) {
        var context = req.app.locals.specialContext;
        req.app.locals.specialContext = null;
        res.render("home.jade", context); 
        // or if you are using ejs
        res.render("home", {context: context}); 
    });

    function middleware(req, res, next) {
        req.app.locals.specialContext = * your context goes here *
        res.redirect("/");
    }

2
Penso che questa sia una cattiva idea perché req.app.locals sembra interessare tutti gli utenti, non solo quello che ha effettuato la richiesta. Sicuramente cancellerai i dati non appena saranno passati all'utente, ma immagino che potresti avere ancora dei conflitti e che mostrano di volta in volta informazioni errate. E se devi cancellarlo comunque, puoi anche semplicemente memorizzarlo nella sessione.
impilatori il

1
effettivamente effettuerà solo la richiesta inviata dagli utenti "unici", anche se 2 o più utenti inviano richieste "contemporaneamente" ogni utente avrà il proprio oggetto richiesta e il suo oggetto locale, in questo modo è completamente sicuro uso
Hussein Dimessi,

req è per un utente unico, ma req.app è per tutti gli utenti.
ZeroCho il

usa express-session per inviare il messaggio
ujjal das

3

È possibile passare piccoli bit di dati coppia chiave / valore tramite la stringa di query:

res.redirect('/?error=denied');

E javascript nella home page può accedervi e modificarne il comportamento di conseguenza.

Nota che se non ti dispiace /categoryrimanere come URL nella barra degli indirizzi del browser, puoi semplicemente eseguire il rendering direttamente invece di reindirizzare. IMHO molte volte le persone usano i reindirizzamenti perché i web framework più vecchi hanno reso difficile la risposta diretta, ma è facile da esprimere:

app.post('/category', function(req, res) {

  // Process the data received in req.body

  res.render('home.jade', {error: 'denied'});
});

Come ha commentato @ Dropped.on.Caprica, l'uso di AJAX elimina la preoccupazione di cambiare l'URL.


Come ho detto in un'altra risposta, le stringhe di query non sembrano buone, poiché non so ancora quanto siano grandi i dati che voglio passare. L'altra soluzione è la più congeniale che ho trovato, ma rompe ancora la mia intenzione di mantenere lo stesso URL.
Tenda Enrique Moreno,

@Dbugger È possibile utilizzare un POST AJAX?
AlbertEngelB,

1

possiamo usare express-session per inviare i dati richiesti

quando si inizializza l'app

const express = require('express');
const app = express();
const session = require('express-session');
app.use(session({secret: 'mySecret', resave: false, saveUninitialized: false}));

quindi prima del reindirizzamento basta salvare il contesto per la sessione

app.post('/category', function(req, res) {
    // add your context here 
req.session.context ='your context here' ;
    res.redirect('/');
});

Ora puoi ottenere il contesto ovunque per la sessione. può ottenere solo da req.session.context

app.get('/', function(req, res) {

    // So prepare the context
var context=req.session.context;
    res.render('home.jade', context);
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.