В настоящее время я выполняю свою аутентификацию следующим образом:

function login(req, res, next) {
  // fetch user from the db
  User.findOne(req.body)
    .exec()   // make query a Promise
    .then((user) => {
      const token = jwt.sign({ username: user.username }, config.jwtSecret);
      return res.json({ token, username: user.username });
    })
    .catch(() => {
      const err = new APIError('Authentication error', httpStatus.UNAUTHORIZED, true);
      return Promise.reject(err);
    });
}

Я пытаюсь стандартизировать свои ошибки с помощью общего класса APIError

import httpStatus from 'http-status';

/**
 * @extends Error
 */
class ExtendableError extends Error {
  constructor(message, status, isPublic) {
    super(message);
    this.name = this.constructor.name;
    this.message = message;
    this.status = status;
    this.isPublic = isPublic;
    this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore.
    Error.captureStackTrace(this, this.constructor.name);
  }
}

/**
 * Class representing an API error.
 * @extends ExtendableError
 */
class APIError extends ExtendableError {
  /**
   * Creates an API error.
   * @param {string} message - Error message.
   * @param {number} status - HTTP status code of error.
   * @param {boolean} isPublic - Whether the message should be visible to user or not.
   */
  constructor(message, status = httpStatus.INTERNAL_SERVER_ERROR, isPublic = false) {
    super(message, status, isPublic);
  }
}

export default APIError;

Как я могу проверить Promise.reject в моем тесте?

describe('# POST /api/v1/auth/login', () => {
it('should return Authentication error', () => {
  return request(app)
    .post('/api/v1/auth/login')
    .send(invalidUserCredentials)
     // following lines are not valid anymore with Promise.reject ..
    .expect(httpStatus.UNAUTHORIZED)
    .then((res) => {
      expect(res.body.message).to.equal('Authentication error');
    });
});
0
user762579 28 Май 2017 в 11:44

2 ответа

Лучший ответ

Вы не обрабатываете ошибку / отклонение вообще. Вам необходимо отправить ошибку Назад. Я бы порекомендовал добавить промежуточное программное обеспечение для обработки ошибок в конце ваших маршрутов в Express, а затем использовать next(err) для перехода к нему.

// at the end of your routes
app.use(function(err, req, res, next) {
  // do whatever you want, but at least send status and message:
    res.status(err.status).json({
        message: err.message,
    });
});

Теперь обработайте ошибку в ваших маршрутах через:

.catch(() => {
  const err = new APIError('Authentication error', httpStatus.UNAUTHORIZED, true);
  return next(err);
});
0
Johannes Merz 28 Май 2017 в 09:59

Теперь он работает нормально, у меня была проблема с обработкой ошибок в express.js ... поскольку проверка типа APIError всегда была ложной ... расширение пакета es6-error вместо Error решает эту проблему Babel ...

< Сильный > APIError.js

import ExtendableError from 'es6-error';  // solve Babel issue w isInstanceOf()
import httpStatus from 'http-status'

class MyExtendableError extends ExtendableError {
  constructor(message, status, isPublic) {
    super(message);
    this.name = this.constructor.name;
    this.message = message;
    this.status = status;
    this.isPublic = isPublic;
    this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore.
    Error.captureStackTrace(this, this.constructor.name);
  }
}

/**
 * Class representing an API error.
 * @extends MyExtendableError
 */
class APIError extends MyExtendableError {
  constructor(message, status = httpStatus.INTERNAL_SERVER_ERROR, isPublic = false) {
    super(message, status, isPublic);
  }
}

export default APIError;

< Сильный > Express.js

// catch 404 and forward to error handler
/* istanbul ignore next  */
app.use((req, res, next) => {
  const err = new APIError('API not found', httpStatus.NOT_FOUND);
  return next(err);
});

// if error is not an instance Of APIError, convert it.
app.use((err, req, res, next) => {
  if (err instanceof expressValidation.ValidationError) {
    // validation error contains errors which is an array of error each containing message[]
    const unifiedErrorMessage = err.errors.map((error) => {
      return error.messages.join('. ');
    }).join(' and ');
    const error = new APIError(unifiedErrorMessage, err.status, true);
    res.status(error.status).json({
      message: err.isPublic ? err.message : httpStatus[err.status],
      stack: (config.env === 'test' || config.env === 'development' ) ? err.stack : {}
    });
  } else if (!(err instanceof APIError)) {
    const apiError = new APIError(err.message, err.status, err.isPublic);
    res.status(apiError.status).json({
      message: err.isPublic ? err.message : httpStatus[err.status],
      stack: (config.env === 'test' || config.env === 'development' ) ? err.stack : {}
    });
  }else {
    res.status(err.status).json({
    message: err.isPublic ? err.message : httpStatus[err.status],
    stack: (config.env === 'test' || config.env === 'development' ) ? err.stack : {}
   });
  }
});

< Сильный > auth.route.js

import express from 'express';
import validate from 'express-validation';
import expressJwt from 'express-jwt';
import paramValidation from '../../../config/param-validation';
import authCtrl from '../controllers/auth.controller';
import config from '../../../config/config';

const router = express.Router();

/** POST /api/auth/login - Returns token if correct username and password is provided */
router.route('/login')
  .post(validate(paramValidation.login), authCtrl.login);

< Сильный > auth.controller.js

function login(req, res, next) {
  // fetch user from the db
  User.findOne(req.body)
    .exec()   // make query a Promise
    .then((user) => {
      const token = jwt.sign({ username: user.username }, config.jwtSecret);
      return res.json({ token, username: user.username });
    })
    .catch(() => {
      const err = new APIError('Authentication error', httpStatus.UNAUTHORIZED, true);
      return next(err);
    });
}

< Сильный > auth.test.js

..
    it('should return Authentication error', () => {
      return request(app)
        .post('/api/v1/auth/login')
        .send(invalidUserCredentials)
        .expect(httpStatus.UNAUTHORIZED)
        .then((res) => {
          expect(res.body.message).to.equal('Authentication error');
        });
    });
...
0
29 Май 2017 в 10:37