【问题标题】:ExpressJS: Can't set headers after they are sentExpressJS:发送后无法设置标题
【发布时间】:2018-02-07 21:15:03
【问题描述】:

我在 ExpressJS 中有一个 API。在该 API 中,我有一个登录端点,当发布到该端点时,我不断收到异常,即标头在发送后无法设置。

我知道这通常是一个回调,它被调用了两次,或者没有从设置了标头的东西正确返回,导致应用程序尝试再次设置它们,但是在我的 /login 端点中我没有这样做。

我不明白为什么会发生这种情况,我很想知道为什么当我读到相同的回复和答案时,我快要拔掉头发了。我希望这是我明显缺少的东西。

import User from '../../models/user';
import { Router } from 'express';
import jwt from 'jsonwebtoken';

export default () => {
  const route = Router();

  route.post('/create', async (req, res, next) => {
    if (!req.body.email || !req.body.password) {
      return res
        .status(400)
        .json({ message: 'username or password is missing' });
    }

    const { email, password } = req.body;
    const count = await User.count({ email });

    if (count > 0) {
      return res.status(409).json({ message: 'email must be unique' });
    }

    const newUser = await new User({ email, password });
    const doc = await newUser.save();

    return res.status(201).json({ type: 'account', attributes: doc });
  });

  route.post('/login', async (req, res, next) => {
    if (req.body.email && req.body.password) {
      const { email, password } = req.body;

      const user = await User.findOne({ email });
      if (user) {
        user.comparePassword(password, isMatch => {
          if (isMatch) {
            const token = jwt.sign(
              { sub: user.id, roles: [], email: user.email },
              process.env.SECRET_KEY,
              { expiresIn: '12h' },
            );

            return res
              .status(200)
              .json({ type: 'account', attributes: { token } });
          }
        });
      }
    }
    res.sendStatus(401);
  });

  return route;
};

【问题讨论】:

    标签: node.js express passport.js


    【解决方案1】:
    import User from '../../models/user';
    import { Router } from 'express';
    import jwt from 'jsonwebtoken';
    
    export default () => {
      const route = Router();
    
      route.post('/create', async (req, res, next) => {
        if (!req.body.email || !req.body.password) {
          return res
            .status(400)
            .json({ message: 'username or password is missing' });
        }
    
        const { email, password } = req.body;
        const count = await User.count({ email });
    
        if (count > 0) {
          return res.status(409).json({ message: 'email must be unique' });
        }
    
        const newUser = await new User({ email, password });
        const doc = await newUser.save();
    
        return res.status(201).json({ type: 'account', attributes: doc });
      });
    
      route.post('/login', async (req, res, next) => {
        if (req.body.email && req.body.password) {
          const { email, password } = req.body;
    
          const user = await User.findOne({ email });
          if (user) {
            return user.comparePassword(password, isMatch => {
              if (isMatch) {
                const token = jwt.sign(
                  { sub: user.id, roles: [], email: user.email },
                  process.env.SECRET_KEY,
                  { expiresIn: '12h' },
                );
    
                return res
                  .status(200)
                  .json({ type: 'account', attributes: { token } });
              } else {
                 return res.status(400)
                   .json({ message: 'username or password is invalid' });
               }
            });
          }
        }
        res.sendStatus(401);
      });
    
      return route;
    };
    

    看看更新后的代码返回丢失在

    return user.comparePassword(password, isMatch => {

    希望它能解决您的问题。

    【讨论】:

    • 如果密码不匹配怎么办,这将返回未定义,客户端将无法从服务器获得响应,导致超时错误
    • 你必须处理 if (isMatch) { } else { // 你的代码的 else 部分 }
    • 我在你的回答中看不到 else 部分
    【解决方案2】:

    这里的问题。您在 comparePassword 中的回调仅在该回调内返回。所以代码仍然运行到res.sendStatus(401),并且在回调完成后它将运行res.status(200).json...

    user.comparePassword(password, isMatch => {
                  if (isMatch) {
                    const token = jwt.sign(
                      { sub: user.id, roles: [], email: user.email },
                      process.env.SECRET_KEY,
                      { expiresIn: '12h' },
                    );
    
                    return res
                      .status(200)
                      .json({ type: 'account', attributes: { token } });
                  }
                });
    

    【讨论】:

      【解决方案3】:

      尝试在用户模型中promisifycomparePassword方法:

      userSchema.methods.comparePassword = function (password) {
      
          return new Promise( function(resolve, reject) {
              resolve(password === this.password);
          });
      
      }
      

      现在您可以使用await 语法来获取承诺结果:

      route.post('/login', async (req, res, next) => {
          if (req.body.email && req.body.password) {
              const { email, password } = req.body;
      
              const user = await User.findOne({ email });
      
              if (user) {
      
                  const isMatch = await user.comparePassword(password);
      
                  if (isMatch) {
                      const token = jwt.sign(
                          { sub: user.id, roles: [], email: user.email },
                          process.env.SECRET_KEY,
                          { expiresIn: '12h' },
                      );
      
                      return res
                          .status(200)
                          .json({ type: 'account', attributes: { token } });
                  }
              }
          }
          res.sendStatus(401);
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-23
        相关资源
        最近更新 更多