Як я переадресовуюсь у expressjs під час проходження певного контексту?


269

Я використовую 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
Перевірте експрес flash: stackoverflow.com/questions/12442716 / ...
tymeJV

Тут має значення термінологія: немає /сторінки. Існує /маршрут, який експрес може обслуговувати, і є шаблон домашньої сторінки, який експрес може надавати. Якщо ви хочете зберегти деякі дані для візуалізації шаблону домашньої сторінки після переадресації, прийнята відповідь, незважаючи на це, сеанси - ваш друг. Вони надають вам сховище даних, яке зберігається в запитах та відповідях для окремих користувачів перегляду, щоб ви могли вносити дані під час /categoryобробки, а потім виймати їх, якщо вони є там під час /передачі.
Майк 'Помакс' Камерманс

Відповіді:


366

Існує кілька способів передачі даних на різні маршрути. Найправильніша відповідь - це, звичайно, рядки запитів. Вам потрібно буде переконатися, що значення правильно кодуютьURIComponent та 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"
        }
     }));
 });

Тож якщо ви хочете перенаправити всі змінні рядки рядка запиту, ви можете просто зробити

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

Існує також можливість використовувати стару особливість експрес, req.flash. Якщо це зробити в нових версіях Express, вам потрібно буде використовувати іншу бібліотеку. По суті це дозволяє налаштувати змінні, які відображатимуться та скидатимуться під час наступного переходу на сторінку. Це зручно для показу помилок користувачам, але знову його видалено за замовчуванням. EDIT: Знайдено бібліотеку, яка додає цю функціональність.

Сподіваємось, це дасть вам загальне уявлення про те, як передавати інформацію у програмі Express.


6
Квірі не відчувають себе добре для передачі контексту, оскільки це може бути великим, як довгий абзац, а то й більше. Що стосується сеансів, то це може спрацювати. але насправді це не вірно, оскільки це не здається правильною метою сеансів ...
Енріке Морено Намет

@Dbugger На жаль, не зрозумів, що ви поставили запитання. Якщо ви турбуєтесь про те, щоб передати занадто багато інформації користувачеві через рядок запитів, можливо, буде краще зберігати дані перевірки в БД, а потім запитувати це, коли ви потрапляєте на основний /маршрут. Інший варіант - зателефонувати за поштовим маршрутом через AJAX та зберегти отримані дані в локальному сховищі чи щось подібне.
AlbertEngelB

13
Хороша відповідь, але я думаю, що сеанси - це кращий підхід, ніж рядки запитів - не виставляйте матеріалів у URL-адресах!
користувач2562923

2
@ user2562923 Я погоджуюсь, сеанси чи пости краще, ніж GET, для проходження контексту навколо. Відповідь була досить розпливчаста, тому я не був впевнений, яку інформацію просила прохаючий.
AlbertEngelB

node js має 2 основних модулі, які генерують рядок запиту
Fareed Alnamrouti

42

Найпростіший спосіб, який я знайшов для передачі даних між 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);

4
Друже, я люблю цю відповідь. Допоміг мені з дірки там - хоча мені справді потрібно більше читати, оскільки моя кишка кричала, щоб я передавав req і переглядав як аргументи для наступного ().
JonRed

1
Дуже гарна і консервативна відповідь! Набагато простіше і набагато безпечніше, ніж інші відповіді.
Triforcey

2
Цей підхід здається більш чистим, але я не впевнений, чи залишить він адресний рядок в останньому шляху, чи закінчиться він/
Danielo515

1
@ Danielo515 це закінчиться на / категоріях, на жаль, тому це насправді те саме, що просто перегляд перегляду безпосередньо в / категоріях ...
Мануель Граф

2
Я не погоджуюся, що ви просто використовуєте роутер як послугу для надання відображеного перегляду, який залишить URL-адресу таким, яким він є, погано ідею таким чином структурувати свій код, мета наступного - перейти до наступного проміжного програмного забезпечення, і ми зазвичай ізолювати нашу логіку бізнесу від логіки маршрутизаторів
Fareed Alnamrouti

9

Мені довелося знайти інше рішення, оскільки жодне із запропонованих рішень насправді не відповідало моїм вимогам з наступних причин:

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

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

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

Тож це моє четверте рішення, яке не страждає жодним із попередніх питань. В основному це передбачає використання тимчасового файлу cookie, для якого вам доведеться спочатку встановити cookie-аналізатор . Очевидно, це означає, що він працюватиме лише тоді, коли ввімкнено файли 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. База даних просто змушує сеанси зберігатися через перезавантаження сервера.
Майк 'Помакс' Камерманс

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

використовувати експрес-сесію для відправки повідомлення
ujjal das

3

Ви можете передати невеликі шматочки даних пари ключ / значення через рядок запиту:

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-адреси.


Як я вже говорив в іншій відповіді, рядки запитів не здаються гарними, оскільки я ще не знаю, наскільки великі дані, які я хочу передати. Ваше інше рішення є більш приємним, що я знайшов, але воно все ще порушує мій намір зберегти ту саму URL-адресу.
Енріке Морено Монт

@Dbugger Можливо, використовувати AJAX POST?
AlbertEngelB

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);
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.