Comment rediriger dans expressjs tout en passant du contexte?

270

J'utilise express pour créer une application web dans node.js. Ceci est une simplification de ce que j'ai:

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('/');
});

Mon problème est le suivant:

Si je trouve que les données envoyées /categoryne sont pas validées, je voudrais passer un contexte supplémentaire à la /page. Comment pourrais-je faire ça? La redirection ne semble autoriser aucun type de paramètre supplémentaire.

Tente Enrique Moreno
la source
1
Découvrez express ' flash: stackoverflow.com/questions/12442716/…
tymeJV
La terminologie compte ici: il n'y a pas de /page. Il existe une /route, qui peut être desservie par express, et il existe un modèle de page d'accueil, qui peut être rendu par express. Si vous souhaitez conserver certaines données pour le rendu du modèle de page d'accueil après une redirection, malgré la réponse acceptée, les sessions sont votre ami. Ils vous donnent un magasin de données qui persiste à travers les demandes et les réponses pour les utilisateurs de navigation individuels afin que vous puissiez mettre des données pendant la /categorymanipulation, puis les retirer si elles sont là pendant la /remise.
Mike 'Pomax' Kamermans

Réponses:

368

Il existe plusieurs façons de transmettre des données à différents itinéraires. La réponse la plus correcte est, bien sûr, les chaînes de requête. Vous devrez vous assurer que les valeurs sont correctement encodéesURIComponent et decodeURIComponent .

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

Vous pouvez accrocher cela dans votre autre itinéraire en obtenant les paramètres envoyés à l'aide de req.query.

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

Pour une manière plus dynamique, vous pouvez utiliser le urlmodule principal pour générer la chaîne de requête pour vous:

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

Donc, si vous souhaitez rediriger toutes les variables de chaîne de requête req, vous pouvez simplement faire

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

Et si vous utilisez Node> = 7.x, vous pouvez également utiliser le querystringmodule principal

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

Une autre façon de le faire est de configurer quelque chose dans la session. Vous pouvez lire comment le configurer ici , mais définir et accéder aux variables est quelque chose comme ceci:

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

Et plus tard après la redirection ...

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

Il y a aussi la possibilité d'utiliser une ancienne fonction d'Express, req.flash. Pour ce faire, dans les versions plus récentes d'Express, vous devrez utiliser une autre bibliothèque. Essentiellement, cela vous permet de configurer des variables qui s'afficheront et se réinitialiseront la prochaine fois que vous vous rendrez sur une page. C'est pratique pour montrer les erreurs aux utilisateurs, mais encore une fois, il a été supprimé par défaut. EDIT: Trouvé une bibliothèque qui ajoute cette fonctionnalité.

J'espère que cela vous donnera une idée générale de la façon de transmettre des informations dans une application Express.

AlbertEngelB
la source
6
Les requêtes ne se sentent pas vraiment bien pour passer le contexte, car cela peut être aussi grand qu'un long paragraphe, voire plus. Quant aux sessions, cela peut fonctionner. mais ça ne me semble pas vraiment bien, car cela ne semble pas être le bon but des sessions ...
Tente Enrique Moreno
@Dbugger Oups, je ne savais pas que vous aviez posé la question. Si vous craignez de transmettre trop d'informations à l'utilisateur via la chaîne de requête, il peut être préférable de stocker les données de validation dans une base de données, puis de l'interroger lorsque vous atteignez l' /itinéraire principal . Une autre option consiste à appeler la route de publication via AJAX et à stocker les données résultantes dans le stockage local ou quelque chose de similaire.
AlbertEngelB
13
Bonne réponse mais je pense que les sessions sont la meilleure approche que les chaînes de requête - n'exposez pas les trucs dans les URL!
user2562923
2
@ user2562923 Je suis d'accord, les sessions ou les POST sont meilleurs que les GET pour passer le contexte. La réponse était assez vague, donc je ne savais pas quel genre d'informations le demandeur faisait circuler.
AlbertEngelB
le nœud js possède 2 modules de base qui génèrent la chaîne de requête
Fareed Alnamrouti
42

La manière la plus simple que j'ai trouvée pour passer des données entre routeHandlers pour next()ne pas avoir besoin de jouer avec la redirection ou les sessions. En option, vous pouvez simplement appeler votre homeCtrl(req,res)au lieu de next()et simplement passer le reqetres

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);
jqualls
la source
4
Buddy, j'adore cette réponse. M'a aidé à sortir d'un trou là-bas - même si j'ai vraiment besoin de faire plus de lecture car mon instinct criait pour que je passe les demandes et les res comme arguments pour next ().
JonRed
1
Réponse très bonne et conservatrice! Beaucoup plus facile et beaucoup plus sûr que les autres réponses.
Triforcey
2
Cette approche semble être la plus propre, mais je ne sais pas si elle laissera la barre d'adresse dans le dernier chemin ou si elle se terminera à/
Danielo515
1
@ Danielo515, cela se terminera malheureusement dans / categories, donc c'est en fait la même chose que de rendre la vue directement dans / categories ...
Manuel Graf
2
Je ne suis pas d'accord que vous utilisez simplement le routeur en tant que service pour afficher une vue déférente qui laissera l'URL telle quelle, c'est une mauvaise idée de structurer votre code de cette façon, le but de la prochaine est de passer au prochain middleware et nous avons généralement isoler notre logique métier de la logique des routeurs
Fareed Alnamrouti
9

J'ai dû trouver une autre solution car aucune des solutions fournies ne répondait réellement à mes besoins, pour les raisons suivantes:

  • Chaînes de requête : il se peut que vous ne souhaitiez pas utiliser de chaînes de requête car les URL peuvent être partagées par vos utilisateurs, et parfois les paramètres de requête n'ont pas de sens pour un autre utilisateur. Par exemple, une erreur telle que ?error=sessionExpiredne devrait jamais être affichée par accident à un autre utilisateur.

  • req.session : vous ne voudrez peut-être pas l'utiliser req.sessioncar vous avez besoin de la dépendance de session express pour cela, ce qui inclut la configuration d'un magasin de sessions (tel que MongoDB), dont vous n'avez peut-être pas du tout besoin, ou peut-être utilisez-vous déjà une personnalisation solution de magasin de session.

  • next () : Vous ne voudrez peut-être pas utiliser next()ou next("router")parce que cela rend simplement votre nouvelle page sous l'URL d'origine, ce n'est pas vraiment une redirection vers la nouvelle URL, plus comme un transfert / réécriture, ce qui peut ne pas être acceptable.

C'est donc ma quatrième solution qui ne souffre d'aucun des problèmes précédents. Fondamentalement, cela implique l'utilisation d'un cookie temporaire, pour lequel vous devrez d'abord installer un analyseur de cookies . Évidemment, cela signifie que cela ne fonctionnera que lorsque les cookies sont activés et avec une quantité limitée de données.

Exemple d'implémentation:

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("/");
}
cprcrack
la source
Aucun magasin de session n'est requis pour express-session. Une base de données fait simplement persister les sessions lors des redémarrages du serveur.
Mike 'Pomax' Kamermans
6

utilisez app.set & app.get

Définition des données

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

Obtenir des données

router.get("/sign", (req, res) => {
  console.log('sign', req.app.get('user'))
});
UA_
la source
2
mauvaise idée de le mettre en œuvre. il peut affecter tous les utilisateurs tous req.app est le même pour tous les utilisateurs. nous pouvons utiliser express-session au lieu de cela.
ujjal das
5

Voici ce que je suggère sans utiliser aucune autre dépendance, juste node et express, utilisez app.locals, voici un exemple:

    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("/");
    }
Hussein Dimessi
la source
2
J'ai l'impression que c'est une mauvaise idée car req.app.locals semble affecter tous les utilisateurs, pas seulement celui qui a fait la demande. Bien sûr, vous effacerez les données dès qu'elles seront transmises à l'utilisateur, mais j'imagine que vous auriez toujours des conflits et des informations incorrectes de temps en temps. Et si vous devez le supprimer, vous pouvez tout aussi bien le stocker dans la session.
stackers
1
en fait, cela n'affectera que la demande envoyée par les utilisateurs "uniques", même si 2 utilisateurs ou plus envoient des demandes en "même temps", chaque utilisateur aura son propre objet de demande et son objet local, de cette façon il est complètement sûr de d'utilisation
Hussein Dimessi
req est pour un utilisateur unique, mais req.app est pour tous les utilisateurs.
ZeroCho
utiliser express-session pour envoyer le message
ujjal das
3

Vous pouvez transmettre de petits bits de données de paire clé / valeur via la chaîne de requête:

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

Et javascript sur la page d'accueil peut y accéder et ajuster son comportement en conséquence.

Notez que si cela ne vous dérange pas de /categoryrester en tant qu'URL dans la barre d'adresse du navigateur, vous pouvez simplement afficher directement au lieu de rediriger. À mon humble avis, les gens utilisent souvent des redirections parce que les cadres Web plus anciens rendaient la réponse directe difficile, mais c'est facile en express:

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

  // Process the data received in req.body

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

Comme l'a commenté @ Dropped.on.Caprica, l'utilisation d'AJAX élimine le problème de changement d'URL.

Peter Lyons
la source
Comme je l'ai dit dans une autre réponse, les chaînes de requête ne semblent pas bonnes, car je ne sais pas encore quelle est la taille des données que je veux transmettre. Votre autre solution est la plus agréable que j'ai trouvée, mais elle brise toujours mon intention de conserver la même URL.
Tente Enrique Moreno
@Dbugger Peut-être utiliser un POST AJAX?
AlbertEngelB
1

nous pouvons utiliser express-session pour envoyer les données requises

lorsque vous initialisez l'application

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

donc avant la redirection, enregistrez simplement le contexte de la session

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

Vous pouvez maintenant obtenir le contexte n'importe où pour la session. il peut être obtenu simplement par req.session.context

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

    // So prepare the context
var context=req.session.context;
    res.render('home.jade', context);
});
ujjal das
la source