Wie leite ich in Expressjs um, während ich einen Kontext übergebe?

269

Ich verwende Express, um eine Web-App in node.js zu erstellen. Dies ist eine Vereinfachung dessen, was ich habe:

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

Mein Problem ist folgendes:

Wenn ich feststelle, dass die gesendeten Daten /categorynicht validiert werden, möchte ich der /Seite einen zusätzlichen Kontext übergeben . Wie könnte ich das machen? Die Umleitung scheint keine zusätzlichen Parameter zuzulassen.

Enrique Moreno Zelt
quelle
1
Check out Express ' flash: stackoverflow.com/questions/12442716/…
tymeJV
Hier kommt es auf die Terminologie an: Es gibt keine /Seite. Es gibt eine /Route, die Express bedienen kann, und es gibt eine Homepage-Vorlage, die Express rendern kann. Wenn Sie einige Daten zum Rendern der Homepage-Vorlage nach einer Umleitung beibehalten möchten, sind Sitzungen trotz der akzeptierten Antwort Ihr Freund. Sie bieten Ihnen einen Datenspeicher, der über Anfragen und Antworten für einzelne Browserbenutzer hinweg bestehen bleibt, sodass Sie Daten während der /categoryVerarbeitung eingeben und dann herausnehmen können, wenn sie während der /Übergabe vorhanden sind.
Mike 'Pomax' Kamermans

Antworten:

366

Es gibt verschiedene Möglichkeiten, Daten an verschiedene Routen weiterzuleiten. Die richtigste Antwort sind natürlich Abfragezeichenfolgen. Sie müssen sicherstellen, dass die Werte ordnungsgemäß cododeURIComponent und decodeURIComponent sind .

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

Sie können dies auf Ihrer anderen Route feststellen, indem Sie die Parameter mithilfe von senden req.query.

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

Für eine dynamischere Methode können Sie das urlKernmodul verwenden, um die Abfragezeichenfolge für Sie zu generieren:

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

Wenn Sie also alle erforderlichen Abfragezeichenfolgenvariablen umleiten möchten, können Sie dies einfach tun

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

Und wenn Sie Node> = 7.x verwenden, können Sie auch das querystringKernmodul verwenden

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

Eine andere Möglichkeit besteht darin, in der Sitzung etwas einzurichten. Sie können hier lesen, wie Sie es einrichten , aber das Festlegen und Zugreifen auf Variablen ist ungefähr so:

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

Und später nach der Weiterleitung ...

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

Es besteht auch die Möglichkeit, eine alte Express-Funktion zu verwenden req.flash. Um dies in neueren Versionen von Express zu tun, müssen Sie eine andere Bibliothek verwenden. Im Wesentlichen können Sie damit Variablen einrichten, die beim nächsten Besuch einer Seite angezeigt und zurückgesetzt werden. Es ist praktisch, um Benutzern Fehler anzuzeigen, aber es wurde standardmäßig wieder entfernt. BEARBEITEN: Es wurde eine Bibliothek gefunden, die diese Funktionalität hinzufügt.

Hoffentlich erhalten Sie dadurch eine allgemeine Vorstellung davon, wie Sie Informationen in einer Express-Anwendung weitergeben können.

AlbertEngelB
quelle
6
Abfragen fühlen sich nicht wirklich in Ordnung an, um den Kontext zu übergeben, da dies so groß wie ein langer Absatz oder sogar mehr sein kann. Bei Sitzungen kann dies funktionieren. aber es fühlt sich nicht wirklich richtig an, da dies nicht der richtige Zweck von Sitzungen zu sein scheint ...
Enrique Moreno Tent
@Dbugger Ups, ich habe nicht bemerkt, dass du die Frage gestellt hast. Wenn Sie befürchten, zu viele Informationen über Querystring an den Benutzer zu übergeben, ist es möglicherweise besser, die Validierungsdaten in einer Datenbank zu speichern und diese dann abzufragen, wenn Sie die Hauptroute /erreichen. Eine andere Möglichkeit besteht darin, die Postroute über AJAX aufzurufen und die resultierenden Daten in localstorage oder ähnlichem zu speichern.
AlbertEngelB
13
Gute Antwort, aber ich denke, Sitzungen sind der bessere Ansatz als Abfragezeichenfolgen - machen Sie keine Inhalte in URLs verfügbar!
user2562923
2
@ user2562923 Ich stimme zu, Sitzungen oder POSTs sind besser als GETs, um den Kontext weiterzugeben. Die Antwort war ziemlich vage, daher war ich mir nicht sicher, welche Art von Informationen der Fragesteller weitergab.
AlbertEngelB
Knoten js hat 2 Kernmodule, die die
Abfragezeichenfolge
42

Der einfachste Weg, Daten zwischen routeHandlern zu übertragen, um sich next()nicht mit Weiterleitungen oder Sitzungen herumschlagen zu müssen. Optional können Sie einfach Ihre homeCtrl(req,res)anstelle von anrufen next()und einfach das reqund übergebenres

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
quelle
4
Kumpel, ich liebe diese Antwort. Hat mir dort aus einem Loch geholfen - obwohl ich wirklich mehr lesen muss, da mein Bauch nach mir schrie, um Req und Res als Argumente für next () zu übergeben.
JonRed
1
Sehr gute und konservative Antwort! Viel einfacher und viel sicherer als die anderen Antworten.
Triforcey
2
Dieser Ansatz scheint sauberer zu sein, aber ich bin nicht sicher, ob er die Adressleiste im neuesten Pfad /
belässt
1
@ Danielo515 es wird leider bei / Kategorien enden, also ist dies eigentlich das gleiche wie nur die Ansicht direkt in / Kategorien zu rendern ...
Manuel Graf
2
Ich bin nicht der Meinung, dass Sie den Router nur als Dienst verwenden, um eine verzögerte Ansicht zu rendern, bei der die URL unverändert bleibt. Es ist eine schlechte Idee, Ihren Code so zu strukturieren. Der Zweck von next besteht darin, zur nächsten Middleware zu wechseln, und wir normalerweise
Isolieren Sie
9

Ich musste eine andere Lösung finden, da keine der bereitgestellten Lösungen aus folgenden Gründen tatsächlich meinen Anforderungen entsprach:

  • Abfragezeichenfolgen : Möglicherweise möchten Sie keine Abfragezeichenfolgen verwenden, da die URLs von Ihren Benutzern gemeinsam genutzt werden können und die Abfrageparameter für einen anderen Benutzer manchmal nicht sinnvoll sind. Zum Beispiel sollte ein Fehler, wie er ?error=sessionExpiredniemals versehentlich einem anderen Benutzer angezeigt werden sollte.

  • req.session : Möglicherweise möchten Sie nicht verwenden, req.sessionda Sie hierfür die Express-Sitzungsabhängigkeit benötigen. Dazu gehört das Einrichten eines Sitzungsspeichers (z. B. MongoDB), den Sie möglicherweise überhaupt nicht benötigen oder den Sie möglicherweise bereits verwenden Session Store-Lösung.

  • next () : Möglicherweise möchten Sie nicht verwenden next()oder next("router")da dies im Wesentlichen nur Ihre neue Seite unter der ursprünglichen URL rendert, handelt es sich nicht wirklich um eine Umleitung zur neuen URL, sondern eher um ein Weiterleiten / Umschreiben, was möglicherweise nicht akzeptabel ist.

Dies ist also meine vierte Lösung, die unter keinem der vorherigen Probleme leidet. Grundsätzlich wird ein temporäres Cookie verwendet, für das Sie zuerst den Cookie-Parser installieren müssen . Dies bedeutet natürlich, dass es nur funktioniert, wenn Cookies aktiviert sind und nur eine begrenzte Datenmenge vorhanden ist.

Implementierungsbeispiel:

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
quelle
Für ist kein Sitzungsspeicher erforderlich express-session. Eine Datenbank sorgt nur dafür, dass Sitzungen bei Serverneustarts bestehen bleiben.
Mike 'Pomax' Kamermans
6

Verwenden Sie app.set & app.get

Daten einstellen

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

Daten abrufen

router.get("/sign", (req, res) => {
  console.log('sign', req.app.get('user'))
});
UA_
quelle
2
schlechte Idee, es umzusetzen. Es kann sich auf alle Benutzer auswirken. Alle req.app ist für alle Benutzer gleich. Wir können stattdessen Express-Session verwenden.
Ujjal das
5

Hier ist, was ich vorschlage, ohne eine andere Abhängigkeit zu verwenden, nur Knoten und Ausdruck, verwenden Sie app.locals, hier ist ein Beispiel:

    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
quelle
2
Ich halte dies für eine schlechte Idee, da req.app.locals anscheinend alle Benutzer betrifft, nicht nur denjenigen, der die Anfrage gestellt hat. Sicher, Sie werden die Daten löschen, sobald sie an den Benutzer weitergegeben werden, aber ich würde mir vorstellen, dass sie immer noch widersprüchlich sind und von Zeit zu Zeit falsche Informationen anzeigen. Und wenn Sie es trotzdem löschen müssen, können Sie es stattdessen auch einfach in der Sitzung speichern.
Stapler
1
Tatsächlich wirkt sich dies nur auf die von den "eindeutigen" Benutzern gesendete Anforderung aus, selbst wenn zwei oder mehr Benutzer "gleichzeitig" Anforderungen senden. Jeder Benutzer hat sein eigenes Anforderungsobjekt und sein lokales Objekt. Auf diese Weise ist dies völlig sicher Verwendung
Hussein Dimessi
req ist für einen eindeutigen Benutzer, aber req.app ist für alle Benutzer.
ZeroCho
Verwenden Sie die Express-Sitzung , um die Nachricht zu senden
ujjal das
3

Sie können kleine Bits von Schlüssel / Wert-Paar-Daten über die Abfragezeichenfolge übergeben:

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

Und Javascript auf der Homepage kann darauf zugreifen und sein Verhalten entsprechend anpassen.

Beachten Sie, dass Sie, wenn es Ihnen nichts ausmacht /category, als URL in der Adressleiste des Browsers zu bleiben, einfach direkt rendern können, anstatt umzuleiten. IMHO verwenden viele Leute Weiterleitungen, weil ältere Web-Frameworks das direkte Reagieren erschwerten, aber es ist im Express einfach:

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

  // Process the data received in req.body

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

Wie @ Dropped.on.Caprica kommentierte, beseitigt die Verwendung von AJAX das Problem der URL-Änderung.

Peter Lyons
quelle
Wie ich in einer anderen Antwort sagte, scheinen Abfragezeichenfolgen nicht gut zu sein, da ich noch nicht weiß, wie groß die Daten sind, die ich übergeben möchte. Ihre andere Lösung ist die kongenialere, die ich gefunden habe, aber sie verstößt immer noch gegen meine Absicht, dieselbe URL beizubehalten.
Enrique Moreno Zelt
@Dbugger Verwenden Sie möglicherweise einen AJAX POST?
AlbertEngelB
1

Wir können Express-Session verwenden , um die erforderlichen Daten zu senden

wenn Sie die App initialisieren

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

Speichern Sie vor der Umleitung einfach den Kontext für die Sitzung

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

Jetzt können Sie den Kontext für die Sitzung überall abrufen. es kann nur durch req.session.context bekommen

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

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