如何在Hapi.js中实现Joi验证?修复代码报错问题
修复Hapi.js中Joi验证failAction的报错问题
嗨,我刚看完你的代码和报错信息,问题出在failAction的返回值不符合Hapi的生命周期规则。Hapi明确要求:在handler执行前的生命周期钩子(比如验证阶段的failAction)里,你不能直接返回一个普通的h.response(),必须明确告诉框架你要接管这个响应,或者抛出错误——否则框架会认为你没有正确处理验证失败的情况,就会抛出你看到的那个错误。
具体修复方案
我给你两种可行的修复方式,你可以选一种适合你的:
方式1:标记响应为"接管模式"
修改你的failAction方法,在返回响应时调用.takeover(),告诉Hapi我们要完全接管这个响应的处理,不再继续后续的生命周期流程:
failAction: (req, h, source, error) => { console.log("Error ::: ", source.details[0].message); return h.response({ code: 0, message: source.details[0].message }).takeover(); // 关键:添加takeover() }
方式2:直接抛出错误(推荐)
这种方式更符合Hapi的设计习惯,你可以直接抛出错误,框架会自动处理响应;如果想要自定义错误格式,也可以用@hapi/boom库来生成标准化的错误响应:
// 先安装@hapi/boom(如果需要的话):npm install @hapi/boom const Boom = require('@hapi/boom'); failAction: (req, h, source, error) => { console.log("Error ::: ", source.details[0].message); // 方式A:抛出普通错误 throw new Error(source.details[0].message); // 方式B:用Boom生成标准化的400错误(推荐) // throw Boom.badRequest(source.details[0].message); }
额外优化:自定义Joi错误提示
另外,你提到希望返回"Email is required"这类友好提示,当前Joi默认的提示是"email" is required,可以通过messages()方法自定义:
const payloadValidator = Joi.object({ email: Joi.string().required().messages({ 'any.required': 'Email is required', 'string.empty': 'Email cannot be empty' }), password: Joi.string().required().messages({ 'any.required': 'Password is required', 'string.empty': 'Password cannot be empty' }) }).options({ allowUnknown: true });
修复后的完整路由代码
把上面的修改整合后,你的路由代码应该是这样的:
const Boom = require('@hapi/boom'); const payloadValidator = Joi.object({ email: Joi.string().required().messages({ 'any.required': 'Email is required', 'string.empty': 'Email cannot be empty' }), password: Joi.string().required().messages({ 'any.required': 'Password is required', 'string.empty': 'Password cannot be empty' }) }).options({ allowUnknown: true }); server.route([ { method: 'POST', path: '/login', config: { tags: ['login', 'auth'], auth: false, validate: { payload: payloadValidator, failAction: (req, h, source, error) => { console.log("Error ::: ", source.details[0].message); // 这里用Boom的方式,你也可以换成takeover的方式 throw Boom.badRequest(source.details[0].message); } } }, handler: async (request, h) => { console.log(request.payload.email); console.log(request.payload.password); // 你的业务逻辑... return h.response({ code: 1, message: 'Login successful' }); } } ]);
这样修改后,验证失败时就会正确返回你想要的提示,也不会再抛出那个生命周期错误了。
内容的提问来源于stack exchange,提问作者Sachin Shah
相关产品推荐
相关产品推荐

