我尝试按照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
答案 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