如何在传递某些上下文时重定向快递?

Enr*_*ent 234 node.js express

我正在使用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('/');
});
Run Code Online (Sandbox Code Playgroud)

我的问题如下:

如果我发现发送的数据/category没有验证,我想传递一些额外的上下文到/页面.我怎么能这样做?重定向似乎不允许任何类型的额外参数.

Alb*_*elB 321

有几种方法可以将数据传递到不同的路径.当然,最正确的答案是查询字符串.您需要确保值正确encodeURIComponentdecodeURIComponent.

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

你可以通过使用发送的参数来阻止你在其他路线中req.query.

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

对于更动态的方式,您可以使用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"
        }
     }));
 });
Run Code Online (Sandbox Code Playgroud)

因此,如果您想重定向所有req查询字符串变量,您可以这样做

res.redirect(url.format({
       pathname:"/",
       query:req.query,
     });
 });
Run Code Online (Sandbox Code Playgroud)

如果您使用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);
 });
Run Code Online (Sandbox Code Playgroud)

另一种方法是在会话中设置一些东西. 您可以在这里阅读如何设置它,但设置和访问变量是这样的:

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

后来重定向......

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

还可以选择使用Express的旧功能req.flash.在较新版本的Express中执行此操作将要求您使用其他库.从本质上讲,它允许您设置将在下次进入页面时显示和重置的变量.向用户显示错误很方便,但默认情况下它已被删除.编辑:找到一个添加此功能的库.

希望这能让您大致了解如何在Express应用程序中传递信息.

  • 很好的答案,但我认为会话是比查询字符串更好的方法 - 不要在URL中公开内容! (10认同)
  • Querys不会觉得通过上下文真的很好,因为这可能和长段一样大,甚至更多.至于会议,这可能会奏效.但它并不是真的感觉正确,因为这似乎不是会议的正确目的...... (5认同)
  • @ user2562923我同意,会话或POST比传递上下文更好于GET.答案很模糊,所以我不确定提问者传递的是什么信息. (2认同)

jqu*_*lls 37

我发现在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);
Run Code Online (Sandbox Code Playgroud)

  • 伙计,我喜欢这个答案.帮助我走出了一个洞 - 虽然我真的需要做更多的阅读,因为我的直觉迫使我传递req和res作为next()的参数. (3认同)
  • 这种方法看起来更干净,但我不确定它是否会在最新路径中留下地址栏,或者它是否会以`/`结尾 (2认同)
  • 我不同意你只是使用路由器作为服务来呈现不同的视图,这将使 URL 保持原样,以这种方式构建你的代码是个坏主意,下一步的目的是转移到下一个中​​间件,我们通常将我们的业务逻辑与路由器逻辑隔离 (2认同)

Cha*_*wki 10

使用 app.set 和 app.get

设置数据

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

获取数据

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

Run Code Online (Sandbox Code Playgroud)

  • 实施它是个坏主意。它可以影响所有用户,所有 req.app 对于所有用户都是相同的。我们可以使用 **express-session** 来代替它。 (3认同)
  • 绝对不要这样做——在 HTTP 服务器中滥用单例值/存储(如 Express 的应用程序对象)可能是我见过的安全漏洞的最常见原因,这是一个很好的演示。想象一下该系统的两个用户,其中一个用户在登录流程中稍稍领先于另一个:第一个用户刚刚点击 GET /sign,而第二个用户在重定向到 /sign 之前处于 GET /facebook/callback。第一个用户的 GET 然后记录第二个用户的信息。哎呀。谢天谢地,这只是日志记录。如果它是通过独特的用途来加密的,那么它就会起作用(这就是会话。) (2认同)

ujj*_*das 10

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

当你初始化应用程序时

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

所以在重定向之前只需保存会话的上下文

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

现在您可以在任何地方获取会话的上下文。它可以通过req.session.context获取

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

    // So prepare the context
var context=req.session.context;
    res.render('home.jade', context);
});
Run Code Online (Sandbox Code Playgroud)


cpr*_*ack 7

我必须找到另一个解决方案,因为提供的解决方案实际上都无法满足我的要求,原因如下:

  • 查询字符串:您可能不想使用查询字符串,因为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("/");
}
Run Code Online (Sandbox Code Playgroud)

  • “express-session”不需要会话存储。数据库只是使会话在服务器重新启动后持续存在。 (2认同)

小智 6

这是我的建议,不使用任何其他依赖项,仅使用 node 和 express,使用 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("/");
    }
Run Code Online (Sandbox Code Playgroud)

  • 我觉得这是一个坏主意,因为 req.app.locals 似乎影响所有用户,而不仅仅是发出请求的用户。当然,您会在将数据传递给用户后立即清除数据,但我想您仍然会遇到冲突并不时显示不正确的信息。如果您无论如何都必须清除它,您不妨将其存储在会话中。 (2认同)