ERR_HTTP_HEADERS_SENT: 发送给客户端 Passport 后无法设置 headers

ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client Passport

这个问题以前有人问过,但无法用前面的清单解决任何问题。

我正在尝试使用 passport-cas 进行身份验证,但我 运行 遇到了一个我真的不知道如何解决的错误。

我认为问题在于底部代码:

user.save((err) => {
    if (err) { return done(err); }
    return done(null, user);
  });

尤其是 done(null, user) 会在用户第一次尝试注册时导致错误。

问题:

如果用户点击登录按钮两次,则完美登录。这样做的原因是因为它第一次抛出 ERR_HTTP_HEADERS_SENT 错误,然后重定向到主页。第二次,如前所述,完美运行,因为用户已经在数据库中,不需要创建。

任何帮助都会很棒,我的代码如下:

passport.js:

passport.use(new(require('passport-cas').Strategy)({
  ssoBaseURL: 'https://domain.edu/cas',
  serverBaseURL: 'http://localhost:8080'
}, function(netid, done) {
  User.findOne({
    netid: netid
  }, function(err, user) {
    if (err) {
      return done(err);
    }
    if (!user) {
      const user = new User({
        netid: netid
      });

      user.save((err) => {
        if (err) { return done(err); }
        return done(null, user);
      });
    }
    return done(null, user);
  });
}));

user.js:

exports.casLogin = function(req, res, next) {
  passport.authenticate('cas', function(err, user) {
    if (err) {
      return next(err);
    }
    if (!user) {
      return res.redirect('/');
    }
    req.logIn(user, function(err) {
      if (err) {
        return next(err);
      }
      return res.redirect('/');
    });
  })(req, res, next);
};

app.js:

const userController = require('./controllers/user');
app.get('/cas', userController.casLogin);

您在此代码中两次调用 done() 回调:

passport.use(new(require('passport-cas').Strategy)({
  ssoBaseURL: 'https://domain.edu/cas',
  serverBaseURL: 'http://localhost:8080'
}, function(netid, done) {
  User.findOne({
    netid: netid
  }, function(err, user) {
    if (err) {
      return done(err);
    }
    if (!user) {
      const user = new User({
        netid: netid
      });

      user.save((err) => {
        if (err) { return done(err); }
        return done(null, user);             // calling it again here
      });
    }
    return done(null, user);                 // calling it first here
  });
}));

问题是您传递给 user.save() 的回调是异步调用的,其中的 return 没有来自父函数的 return。因此,继续执行父函数,并在您不希望它被调用时调用 return done(null, user)

您可以通过添加另一个 return.

来修复它
passport.use(new(require('passport-cas').Strategy)({
  ssoBaseURL: 'https://domain.edu/cas',
  serverBaseURL: 'http://localhost:8080'
}, function(netid, done) {
  User.findOne({
    netid: netid
  }, function(err, user) {
    if (err) {
      return done(err);
    }
    if (!user) {
      const user = new User({
        netid: netid
      });

      user.save((err) => {
        if (err) { return done(err); }
        return done(null, user);
      });
      return;                            // <=== add this return
    }
    return done(null, user);
  });
}));

您也可以将 if (!user) 变成 if/else 而不是添加上面的 return.