我如何重定向在expressjs而传递一些上下文?

我正在使用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中发送的数据不验证,我想向/页传递一些额外的上下文。我怎么能这样做呢?重定向似乎不允许任何类型的额外参数。

557537 次浏览

你可以通过查询字符串传递少量的键/值对数据:

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

主页上的javascript可以访问它并相应地调整它的行为。

注意,如果你不介意/category作为浏览器地址栏中的URL,你可以直接渲染而不是重定向。恕我直言,很多时候人们使用重定向,因为旧的web框架使直接响应变得困难,但表达起来很容易:

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


// Process the data received in req.body


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

@Dropped.on。Caprica评论说,使用AJAX消除了URL更改问题。

有几种方法可以将数据传递到不同的路由。当然,最正确的答案是查询字符串。你需要确保值是正确的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,
});
});

如果你使用的是节点>= 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应用程序中传递信息。

我发现在routeHandlers之间传递数据的最简单的方法是使用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);

我不得不寻找另一个解决方案,因为所提供的解决方案实际上没有一个满足我的要求,原因如下:

  • 查询字符串:您可能不想使用查询字符串,因为url可能由您的用户共享,而且有时查询参数对不同的用户没有意义。例如,像?error=sessionExpired这样的错误永远不应该意外地显示给另一个用户。

  • < >强要求的事情。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("/");
}

下面是我的建议,不使用任何其他依赖,只是节点和表达式,使用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("/");
}

使用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'))
});


我们可以使用express-session来发送所需的数据

当你初始化应用程序

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);
});
 app.get('/category', function(req, res) {
var string = query
res.redirect('/?valid=' + string);
});

在ejs中,你可以直接使用valid:

<% var k = valid %>
我用了一个非常简单但有效的技巧 在我的App.js(我的入口点) 我定义了一个变量

let authUser = {};

然后我分配给它从我的路由页面(像成功登录后)

authUser = matchedUser

这可能不是最好的方法,但它符合我的需求。

2021年< p >更新: 我尝试了url.formatquerystring,它们都已弃用,相反,我们可以使用URLSearchParams

const {URLSearchParams} = require('url')
               

app.get('/category', (req, res) =>{
const pathname = '/?'
const components ={
a:"a",
b:"b"
}


const urlParameters = new URLSearchParams(components)
res.redirect(pathname + urlParameters)
})