コンテキストを渡しながら、Expressjsでリダイレクトするにはどうすればよいですか?


270

Expressを使用して、node.jsでWebアプリを作成しています。これは私が持っているものを単純化したものです:

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

私の問題は次のとおりです:

送信されたデータ/categoryが検証されない場合、/ページに追加のコンテキストを渡したいと思います。どうすればこれを行うことができますか?リダイレクトでは、どのような種類の追加パラメーターも許可されていないようです。


1
エクスプレスチェックアウトflashstackoverflow.com/questions/12442716/...
tymeJV

ここでは用語が重要です/。ページはありません。/Expressがサービスを提供できるルートがあり、Expressがレンダリングできるホームページテンプレートがあります。リダイレクト後にホームページテンプレートをレンダリングするためのデータを保持したい場合、受け入れられた回答にもかかわらず、セッションはあなたの友達です。それらは、個々のブラウジングユーザーの要求と応答にわたって永続するデータストアを提供します。これにより、処理中にデータを入れ、処理中にそこにある場合はデータを/category取り出すことができ/ます。
マイク 'Pomax'カマーマンズ

回答:


368

さまざまなルートにデータを渡す方法はいくつかあります。もちろん、最も正しい答えはクエリ文字列です。値が適切にencodeURIComponentdecodeURIComponentであることを確認する必要があります。

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

を使用して送信されたパラメータを取得することにより、他のルートで問題を回避できますreq.query

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

より動的な方法では、urlコアモジュールを使用してクエリ文字列を生成できます。

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

したがって、すべてのreqクエリ文字列変数をリダイレクトする場合は、簡単に行うことができます

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

また、Node> = 7.xを使用してquerystringいる場合は、コアモジュールも使用できます

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

それを行う別の方法は、セッションで何かを設定することです。 あなたはここそれを設定する方法を読むことができますが、変数を設定してアクセスすることは次のようなものです:

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

そして後でリダイレクトの後...

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

Expressの古い機能を使用するオプションもありますreq.flash。新しいバージョンのExpressでこれを行うには、別のライブラリを使用する必要があります。基本的に、次にページに移動したときに表示およびリセットされる変数を設定できます。ユーザーにエラーを表示するのに便利ですが、これもデフォルトで削除されています。編集:この機能を追加するライブラリが見つかりました。

うまくいけば、Expressアプリケーションで情報をやり取りする方法の概要がわかるでしょう。


6
クエリは、長いパラグラフと同じくらい大きくなる可能性があるため、コンテキストを渡しても大丈夫とは思われません。セッションに関しては、それはうまくいくかもしれません。しかし、これはセッションの正しい目的とは思えないため、実際には正しくありません...
エンリケモレノテント

@Dbuggerおっと、質問したことに気づかなかった。クエリ文字列を介してユーザーに渡す情報が多すぎることが心配な場合は、検証データをDBに保存し、メイン/ルートに到達したときにクエリを実行することをお勧めします。もう1つのオプションは、AJAXを介してポストルートを呼び出し、結果のデータをlocalstorageなどに保存することです。
AlbertEngelB 2013

13
良い答えですが、セッションはクエリ文字列よりも優れたアプローチだと思います-URLの内容を公開しないでください!
user2562923 2014

2
@ user2562923同意します。コンテキストを渡すには、セッションまたはPOSTがGETよりも優れています。答えはかなり曖昧だったので、質問者がどのような情報を伝えているのかわかりませんでした。
AlbertEngelB 14

ノードjsには、クエリ文字列を生成する2つのコアモジュールがあります
Fareed Alnamrouti 2017年

42

routeHandler間でデータを受け渡す最も簡単な方法はnext()、リダイレクトやセッションを混乱させる必要がないことです。オプションで、homeCtrl(req,res)代わりにを呼び出してnext()、単にreqres

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
バディ、私はこの答えが大好きです。そこの穴から私を助けてくれました-私の腸がnext()の引数としてreqとresを渡すように叫んでいたので、本当にもっと読む必要があります。
JonRed 2014年

1
非常に良い、保守的な答えです!他の回答よりもはるかに簡単で安全です。
Triforcey 2016年

2
このアプローチはより/
すっきりしているように見え

1
@ Danielo515残念ながら/ categoriesで終了するため、これは実際に/ categoriesに直接ビューをレンダリングするのと同じです...
Manuel Graf

2
ルーターをサービスとして使用して、URLをそのままにする遅延ビューをレンダリングすることに同意しません。このようにコードを構造化することは悪い考えです。次の目的は、次のミドルウェアに移動することであり、通常はビジネスロジックをルーターロジックから分離する
Fareed Alnamrouti 2017年

9

次の理由により、提供されたソリューションが実際に要件を満たしていないため、別のソリューションを見つける必要がありました。

  • クエリ文字列:ユーザーがURLを共有する可能性があるため、クエリ文字列を使用したくない場合があります。また、クエリパラメータが別のユーザーにとって意味をなさない場合があります。たとえば、誤っ?error=sessionExpiredて他のユーザーに表示してはならないエラーなど。

  • req.session:セッションストア(MongoDBなど)のセットアップを含む、このためのエクスプレスセッションの依存関係req.sessionが必要なため、使用しない場合があります。これは、まったく必要ない場合や、すでにカスタムを使用している場合があります。セッションストアソリューション。

  • next():使用したくない場合があります。next()またはnext("router")、これは基本的に新しいページを元のURLの下にレンダリングするだけであるため、実際には新しいURLへのリダイレクトではなく、転送/書き換えのように、許容できない場合があります。

したがって、これは以前の問題に悩まされない私の4番目のソリューションです。基本的に、一時的なCookieを使用する必要があります。そのためには、最初にcookie-parserをインストールする必要があります。これは明らかに、Cookieが有効になっていて、データ量が限られている場合にのみ機能することを意味します。

実装例:

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

にはセッションストアは必要ありませんexpress-session。データベースは、サーバーの再起動後もセッションを維持します。
マイク 'Pomax'カマーマンズ

6

app.setとapp.getを使用

設定データ

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

データを取得する

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

2
それを実装するのは悪い考えです。すべてのユーザーに影響を与える可能性があります。すべてのreq.appはすべてのユーザーで同じです。これの代わりに高速セッションを使用できます。
ujjal das

5

他の依存関係を使用せずに私が提案するものは次のとおりです。ノードと表現だけで、app.localsを使用してください。ここに例を示します。

    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
req.app.localsは、リクエストを行ったユーザーだけでなく、すべてのユーザーに影響を与えるため、これは悪い考えだと思います。確かに、ユーザーに渡されたらすぐにデータをクリアしますが、それでも競合し、不正確な情報が時々表示されると思います。とにかくそれをクリアする必要がある場合は、代わりにセッションに保存することもできます。
スタッカー

1
実際には、2人以上のユーザーが「同時に」リクエストを送信した場合でも、「ユニークな」ユーザーが送信したリクエストにのみ影響します。各ユーザーは独自のリクエストオブジェクトとそのローカルオブジェクトを持っているため、完全に安全です。使用
フセインディメッシ

reqは一意のユーザー用ですが、req.appはすべてのユーザー用です。
ZeroCho

express-sessionを使用してメッセージを送信
ujjal das

3

クエリ文字列を介して、キーと値のペアの小さなデータを渡すことができます。

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

そして、ホームページのJavaScriptはそれにアクセスし、それに応じてその動作を調整できます。

/categoryブラウザーのアドレスバーにURLとしてとどまることを気にしない場合は、リダイレクトする代わりに直接レンダリングすることができます。以前のWebフレームワークでは直接応答が困難になったため、IMHOは何度もリダイレクトを使用しますが、簡単に言うと次のようになります。

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

  // Process the data received in req.body

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

@ Dropped.on.Capricaがコメントしたように、AJAXを使用すると、URLの変更に関する懸念がなくなります。


別の回答で述べたように、渡すデータの大きさがまだわからないため、クエリ文字列は適切ではないようです。あなたの他の解決策は私が見つけたより親切なものですが、それでも同じURLを維持するという私の意図を壊します。
エンリケモレノテント

@DbuggerおそらくAJAX POSTを使用しますか?
AlbertEngelB 2013

1

エクスプレスセッションを使用して必要なデータを送信できます

アプリを初期化するとき

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

リダイレクトの前に、セッションのコンテキストを保存してください

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

これで、セッションのどこでもコンテキストを取得できます。req.session.contextだけで取得できます

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

    // So prepare the context
var context=req.session.context;
    res.render('home.jade', context);
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.