Mongoose子Schema的pre 'save'钩子调用静态encrypt函数报错求助
子Schema的pre save钩子中调用自定义加密函数问题
问题描述
在passwordSchema的pre 'save'钩子中调用自定义encrypt静态函数时,报错this.encrypt不是函数。相关代码如下:
pre钩子代码
passwordSchema.pre('save', async function() { if (this.isModified('password')) { try { this.password = this.encrypt(this.password); } catch (error) { throw new Error('Error while encrypting the password : ' + error.message); } } if (this.isModified('login')) { try { this.login = passwordSchema.encrypt(this.login); } catch (error) { throw new Error('Error while encrypting the login : ' + error.message); } } });
encrypt静态函数
passwordSchema.statics.encrypt = function(password) { const cipher = crypto.createCipheriv('aes-256-cbc', CRYPTO_AES); let encryptedPassword = cipher.update(password, 'utf8', 'hex'); encryptedPassword += cipher.final('hex'); return encryptedPassword; };
passwordSchema定义
const passwordSchema = new mongoose.Schema({ login: { type: String, required: [true, "Login required"] }, password: { type: String, required: [true, "Password required"] }, commentaire: { type: String } });
额外说明
该passwordSchema未导出,作为子Schema被collectionSchema使用:
const collectionSchema = new mongoose.Schema( { [...], passwords: [passwordSchema] }, { timestamps: true } );
尝试过使用constructor以及类似Password.encrypt的方式,仍无法解决,需找到在pre 'save'钩子中调用该静态函数的正确方法。
解决方案
核心问题
子文档实例的this指向自身,而静态函数挂载在Schema的statics对象上,子Schema未生成独立模型时,直接通过实例或Schema调用会存在指向问题。以下是几种可行方案:
方案一:将encrypt改为实例方法
把加密逻辑定义为Schema的methods,子文档实例可直接通过this.encrypt调用:
// 替换statics.encrypt为methods.encrypt passwordSchema.methods.encrypt = function(str) { const cipher = crypto.createCipheriv('aes-256-cbc', CRYPTO_AES); let encryptedStr = cipher.update(str, 'utf8', 'hex'); encryptedStr += cipher.final('hex'); return encryptedStr; }; // 修改后的钩子代码 passwordSchema.pre('save', async function() { if (this.isModified('password')) { try { this.password = this.encrypt(this.password); } catch (error) { throw new Error('Error while encrypting the password : ' + error.message); } } if (this.isModified('login')) { try { this.login = this.encrypt(this.login); } catch (error) { throw new Error('Error while encrypting the login : ' + error.message); } } });
方案二:提取为独立工具函数
将加密逻辑抽成单独函数,直接在钩子中调用,同时可按需挂载到statics上:
// 独立加密函数 function encryptStr(str) { const cipher = crypto.createCipheriv('aes-256-cbc', CRYPTO_AES); let encryptedStr = cipher.update(str, 'utf8', 'hex'); encryptedStr += cipher.final('hex'); return encryptedStr; } // 钩子中调用 passwordSchema.pre('save', async function() { if (this.isModified('password')) { try { this.password = encryptStr(this.password); } catch (error) { throw new Error('Error while encrypting the password : ' + error.message); } } if (this.isModified('login')) { try { this.login = encryptStr(this.login); } catch (error) { throw new Error('Error while encrypting the login : ' + error.message); } } }); // 若后续需要模型级调用,仍可挂载statics passwordSchema.statics.encrypt = encryptStr;
方案三:通过父模型间接调用(不推荐)
如果坚持使用静态函数,可通过父模型的Schema路径找到子Schema的statics,但耦合性高:
passwordSchema.pre('save', async function() { // 通过父文档的构造函数找到子Schema的静态方法 const encryptFn = this.parent().constructor.schema.path('passwords').schema.statics.encrypt; if (this.isModified('password')) { try { this.password = encryptFn(this.password); } catch (error) { throw new Error('Error while encrypting the password : ' + error.message); } } if (this.isModified('login')) { try { this.login = encryptFn(this.login); } catch (error) { throw new Error('Error while encrypting the login : ' + error.message); } } });
内容的提问来源于stack exchange,提问作者user14766108
相关产品推荐
相关产品推荐

