Как перенаправить в expressjs при передаче некоторого контекста?

Я использую express для создания веб-приложения в node.js. Это упрощение того, что у меня есть:

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

Существует несколько способов передачи данных по различным маршрутам. Самый правильный ответ - это, конечно, строки запроса. Вы должны убедиться, что значения правильно encodeURIComponent и decodeURIComponent.

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 потребуется использовать другую библиотеку. По сути, это позволяет вам устанавливать переменные, которые будут отображаться, и reset при следующем переходе на страницу. Это удобно для показа ошибок пользователям, но опять же было удалено по умолчанию. EDIT: Найден библиотеку, которая добавляет эту функциональность.

Надеюсь, это даст вам общее представление о том, как передавать информацию в приложении Express.

Ответ 2

Самый простой способ, с помощью которого я нашел передачу данных между routeHandlers для использования next(), не нужно связывать с перенаправлением или сеансами. При желании вы можете просто вызвать homeCtrl(req,res) вместо next() и просто передать req и res

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

Ответ 3

Мне нужно было найти другое решение, потому что ни одно из предложенных решений не соответствовало моим требованиям по следующим причинам:

  • Строки запроса. Возможно, вы не захотите использовать строки запроса, поскольку URL-адреса могут быть общими для ваших пользователей, а иногда параметры запроса не имеют смысла для другого пользователя. Например, ошибка, такая как ?error=sessionExpired, никогда не должна отображаться другому пользователю случайно.

  • req.session: вы можете не захотеть использовать req.session, потому что для этого вам нужна зависимость express-session, которая включает в себя настройку хранилища сеансов (например, MongoDB), чего вы не можете нужно вообще, или, может быть, вы уже используете специальное решение для хранения сеансов.

  • next(): Возможно, вы не захотите использовать next() или next("router"), потому что это, по сути, просто отображает вашу новую страницу под исходным URL-адресом, на самом деле это не перенаправление на новый URL-адрес, а скорее пересылка/перезапись, что может быть неприемлемо.

Так что это мое четвертое решение, которое не страдает ни от одной из предыдущих проблем. В основном это связано с использованием временного файла 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("/");
}

Ответ 4

Вот то, что я предлагаю без использования какой-либо другой зависимости, просто узел и экспресс, используйте 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("/");
    }

Ответ 5

Вы можете передавать небольшие биты данных пары ключ/значение через строку запроса:

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

И javascript на домашней странице может получить доступ к этому и соответствующим образом скорректировать его поведение.

Обратите внимание, что если вы не возражаете /category оставаться в качестве URL-адреса в адресной строке браузера, вы можете просто визуализировать напрямую, а не перенаправлять. 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.

Ответ 6

Одним из решений является промежуточное программное обеспечение анализатора тела, которое передает данные в виде объекта JSON

var express = require('express');
var jade = require('jade');
var http = require("http");
const bodyParser = require('body-parser') //requiring body parser 


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
  //pass the data as an json object 
  res.redirect('/', { data: data });
});