5

我有一个非常奇怪的会话问题——一些奇怪的跨会话问题让我感到困惑。

基本上我有一个 express 3 应用程序,其中我有 2 个看似无关的东西——一个是标准的联系表格,有人可以用它给我发电子邮件,另一个是对 mailchimp 的 API 调用,以便在他们下订单时添加订阅者。这是 2 个完全不同的调用/操作。

在我的联系表顶部,我检查了变量“错误”,我可以在控制器代码中使用它来表示诸如“无效电子邮件”或其他错误消息之类的内容。我的联系表单有 2 个控制器操作 - 一个用于 GET,它显示表单,一个用于 POST,它提交并显示错误(如果有)。

问题是这样的 - 当我最初加载联系表格时,我看到这条消息:“错误:someone@example.com 已经订阅了一般列表。单击此处更新您的个人资料。” 这是一条 MailChimp 消息 - 不仅与流程无关,而且与我的会话无关!如果回头客下订单并已订阅,则可能会发生此错误。据我所知,我从来没有向他们展示过这条消息,实际上没有存储它。所以我很困惑。

需要注意的一件事是,在从支付网关(因此不是常规会话用户)接收到 xml 文件时,从节点服务器调用订单部分 - 所以也许有一些我不理解的会话内部结构。

代码如下,但这里是问题的摘要。没有激活用户会话的节点服务器正在对 mailchimp 进行 API 调用以使用此模块添加订阅者- 通常同一封电子邮件将被订阅两次,因此 mailchimp 将回复“已订阅”消息,我 *不要*t 存储或加载 Express 的错误局部变量。然后,用户访问该站点,转到联系表单,该表单检查该用户是否有任何错误消息来自该用户尝试提交缺少字段的表单 - 他们会看到显示另一个人的电子邮件地址的 mailchimp 消息。

这是相关的代码。

应用程序.js:

var express = require("express"),
flash = require("connect-flash");

...

app.use(flash());

...

app.use(function(req, res, next) {
  var msgs;
  msgs = req.session.messages || [];
  res.locals.messages = msgs;
  res.locals.hasMessages = !!msgs.length;
  req.session.messages = [];
  return next();
});

...

app.get("/contact", express.csrf(), routes.main.contact);
app.post("/contact", express.csrf(), routes.main.submit);

联系表格控制器:

exports.contact = function(req, res) {
    res.locals.token = req.session._csrf;
    res.render('main/contact');
};

exports.submit = function(req, res) {

  var send = function(message, fn) {
    var sendgrid = new SendGrid(settings.sendgrid_username, settings.sendgrid_password);
    sendgrid.send({
      to: settings.contact_email,
      from: message.email,
      subject: 'Contact Message',
      text: message.message
    }, fn);
  };

  var validate = function(message) {
    var v = new Validator(),
      errors = []
      ;

    v.error = function(msg) {
      errors.push(msg);
    };

    v.check(message.name, 'Please enter your name').len(1, 100);
    v.check(message.email, 'Please enter a valid email address').isEmail();
    v.check(message.message, 'Please enter a valid message').len(1, 1000);

    return errors;
  };

  function render() {
    res.locals.token = req.session._csrf;
    res.render('main/contact', locals);
  }

  var message = req.body.message,
    errors = validate(message),
    locals = {}
    ;

  if (errors.length === 0) {
    send(message, function(success) {
      if (!success) {
        locals.error = 'Error sending message';
        locals.message = message;
      } else {
        locals.notice = 'Your message has been sent.';
      }
      render();
    });
  } else {
    locals.error = 'Your message has errors:';
    locals.errors = errors;
    locals.message = message;
    render();
  }
};

联系表:

{% if error or notice %}
<div id="message" class="alert alert-{% if error %}error{% else %}success{% endif %} ">
  <button type="button" class="close" data-dismiss="alert">×</button>
  <h4>{% if error %}{{ error }}{% else %}{{ notice }}{% endif %}</h4>
  {% if errors %}
  <ul>
  {% for e in errors %}
    <li>{{ e }}</li>
  {% endfor %}
  </ul>
  {% endif %}
</div>
{% endif %}

<form method="post">
...

订单表单控制器(成功订单时由支付网关 API 调用 - 从未由用户直接调用)

var joinNewsletter = function(data) {

  try {
      var api = new MailChimpAPI(settings.mailchimp_api, { version : '1.3', secure : false });
      api.listSubscribe({
        id: settings.mailchimp_list_id,
        email_address: data.email,
        merge_vars: {
          fname: data.first,
          lname: data.last
        },
        double_optin: data.optin || false
      }, function() {});
  } catch (error) {
      console.log(error.message);
  }

};
...
 joinNewsletter({
    email: order.email,
    first: order.fname,
    last: order.lname
  });
4

1 回答 1

2

Oh good god I figured it out after a looooot of debugging. The issues are twofold:

  • The MailChimpAPI module has a bug - when an error is received it creates this code:

    error = new Error(message || (message = ''));

The error var is undeclared so it's hitting the global error var.

  • The view code checks if 'error' exists and prints it - that was my own variable. But apparently in the inner mechanism of Express it checks for the global error var.

It seems that error is being handled as an app.locals variable hence bridging user sessions.

I am fixing it by a) patching the MailChimp helper code and filing a bug report and b) making sure to not use 'error' as a view variable ever again.

Woah.

于 2013-05-29T23:00:08.340 回答