重构Express中间件提供了“无法设置未定义的属性”

时间:2019-05-18 10:01:45

标签: javascript node.js express

我尝试按照CodeClimate的建议在Express路由中重构中间件,以避免重复的代码,但是如果我在静态类方法中使用TypeError: Cannot set property "checkUser" of undefined属性,则重构的代码会给出this

我在Express应用中使用PostgreSQL,pg-promise,bcrypt和jwt

用于抽象我的中间件的模块

  static routeCallbacks(...methods) {
    const callbacks = methods.map(method => (...args) => {
      method(...args);
    });
    return callbacks;
  }
}

抽象中间件

import validateUserRequest from '../data/users';
import authenticateUsers from '../auth/users';
import middleware from './middleware';

export default class Users {
...

   static signinClients() {
    const signin = middleware.routeCallbacks(validateUserRequest.signIn, authenticateUsers.signIn);
    return signin;
  }

...
}
上面的

helper方法

import protocol from '../helpers/response';
import checkRequest from '../helpers/checkRequest';

export default class ValidateUserRequest {
...

 static signIn(req, res, next) {
    const { userEmail, userPassword } = req.body;
    const emailErr = checkRequest.checkEmailFormat(userEmail, 'Email');
    const passwordErr = checkRequest.checkPassword(userPassword, 'Password');
    const findError = checkRequest.findError(emailErr, passwordErr);
    if (findError) protocol.err400Res(res, findError);
    else next();
  }

...
}

import database from '../db/pgConnect';
import protocol from '../helpers/response';
import queries from '../helpers/queries';

export default class AuthenticateUsers {
...

  static async signIn(req, res, next) {
    const { userEmail } = req.body;
    const checkUserQuery = queries.findClientByEmail();
    this.checkUser = await database.queryOneORNone(checkUserQuery, [userEmail]);
    if (!this.checkUser) return protocol.err404Res(res, errors.userNotExists('User'));
    return next();
  }

...
}

中间件之后的控制器

import database from '../db/pgConnect';
import password from '../helpers/bcrypt';
import token from '../helpers/jwt';
import authenticateUsers from '../auth/users';
import protocol from '../helpers/response';
import errors from '../helpers/errorMessage';
import models from '../models/users';
import queries from '../helpers/queries';

export default class Users {
...

 static async signIn(req, res) {
    const { userPassword } = req.body;
    const { checkUser } = authenticateUsers;
    const verifyPassword = await password.compare(checkUser.password, userPassword);
    if (!verifyPassword) return protocol.err400Res(res, errors.wrongPassword());
    const signInRes = await models.createUserDataResPostgre(checkUser);
    const newToken = await token.generate(checkUser.id);
    return protocol.auth200Res(res, signInRes, newToken);
  }

...
}

我的路线(重构后无法设置未定义错误的属性checkUser

import userController from '../controllers/users';
import router from './router';
import userMiddleware from '../middleware/users';

router.post('/auth/signin', userMiddleware.signinClients(), userController.signIn);

...
export default router;

我的路线(在重构之前可以正常使用)

import userController from '../controllers/users';
import router from './router';
import userMiddleware from '../middleware/users';

router.post('/auth/signin', (...args) => { validateUserRequest.signIn(...args) }, 
(...args) => { authenticateUsers.signIn(...args) }, userController.signIn);

...
export default router;

由于代码基本上与重构相同,因此我应该得到状态码200而不是500

1 个答案:

答案 0 :(得分:0)

问题是您的this类中的AuthenticateUsers未绑定到您的类,因此未定义。因此,与其直接传递signIn函数,不如将它们绑定到各自的类:

const signin = middleware.routeCallbacks(validateUserRequest.signIn.bind(validateUserRequest), authenticateUsers.signIn.bind(authenticateUsers));

也许首先考虑这个简单的例子:

class TestClass {
    static test() {
        try {
            console.log(this);
            this.tmpData = "some data";
            console.log(this.tmpData);
        } catch (err) {
            console.log("caught error: " + err);
        }
    }
}

const fn = TestClass.test;
console.log("invoking unbound fn:");
fn();
console.log("------------------------------");
const fnBound = TestClass.test.bind(TestClass);
console.log("invoking bound fn:");
fnBound();

这将打印:

invoking unbound fn:
undefined
caught error: TypeError: Cannot set property 'tmpData' of undefined
------------------------------
invoking bound fn:
[Function: TestClass]
some data