在 API 开发过程中,异常处理是一个十分重要且不可避免的问题。而 Hapi.js 是目前比较热门的 Node.js 框架之一,在 Hapi.js 中实现自定义异常处理也是一个比较常见的需求。本文将会介绍 Hapi.js 中实现自定义异常处理的技巧和优化方案。
Hapi.js 中的异常处理
在 Hapi.js 的请求处理链路中,如果出现了异常,Hapi.js 会通过回调函数的方式返回异常信息。以下是一个简单的示例代码:
// javascriptcn.com 代码示例 server.route({ method: 'GET', path: '/users', handler: async function(request, h) { throw new Error('出错了'); } }); server.start();
运行上面的代码,访问 http://localhost:3000/users
将会抛出一个异常:
{"statusCode":500,"error":"Internal Server Error","message":"An internal server error occurred"}
可以看到,Hapi.js 默认将异常信息封装成了一个 JSON,返回给了客户端。但是在实际开发场景中,这样的异常信息并不能满足我们的需求。因此,我们需要进行自定义异常处理。
自定义异常处理
在 Hapi.js 中,实现自定义异常处理可以使用 onPreResponse
方法,该方法会在回包(response)被发送给客户端之前被调用。在该方法中,我们可以对异常信息进行处理,并返回给客户端自定义的异常信息。以下是一个简单的示例代码:
// javascriptcn.com 代码示例 server.ext('onPreResponse', function(request, h) { const { response } = request; if (!response.isBoom) { return response; } const { output } = response; const { statusCode, payload } = output; const error = { code: payload.code || statusCode, message: payload.message || payload.error, }; return h.response({ error }).code(statusCode); }); server.route({ method: 'GET', path: '/users', handler: async function(request, h) { throw Boom.badRequest('参数错误', { code: 40001 }); } }); server.start();
在上面的代码中,我们通过 server.ext
方法注册了一个 onPreResponse
方法。在该方法中,我们首先判断响应是否为错误响应(使用 Boom.js 创建的响应对象都会被封装成错误响应),如果是则将其转换为自定义的异常返回。在上述示例中,我们通过 Boom.badRequest
创建了一个错误响应,其中指定了错误码({ code: 40001 }
),然后将该错误响应抛出。访问 http://localhost:3000/users
可以看到以下响应:
{ "error": { "code": 40001, "message": "参数错误" } }
上述代码中的 Boom
对象是 Hapi.js 内置的一个异常处理工具,可以通过其提供的方法创建各种类型的异常响应。
优化方案
在上面的示例代码中,我们只是简单地将 Hapi.js 默认错误响应进行了转换,但是实际情况可能并不是这样简单的。因此,我们需要考虑如何优化自定义异常处理的方案。
定义通用异常响应
在实际开发中,我们经常会遇到一些常见的异常类型,例如参数错误、权限不足、服务不可用等。为了方便统一处理这些异常类型,我们可以定义一个通用的异常响应,然后根据不同的异常类型进行赋值。以下是一个简单的示例代码:
// javascriptcn.com 代码示例 class HttpError extends Error { constructor(status, message, code) { super(message); this.status = status; this.code = code; } } class BadRequestError extends HttpError { constructor(message, code) { super(400, message, code); } } // 其他异常类型类似 server.ext('onPreResponse', function(request, h) { const { response } = request; if (!response.isBoom) { return response; } const { output } = response; const { res, payload } = output; const error = { code: payload.code || res.statusCode, message: payload.message || payload.error, }; return h.response({ error }).code(res.statusCode); }); server.route({ method: 'GET', path: '/users', handler: async function(request, h) { throw new BadRequestError('参数错误', '40001'); } }); server.start();
在上面的代码中,我们定义了一个 HttpError
类和 BadRequestError
类,前者是所有异常类型的基类,后者继承自 HttpError
,表示参数错误异常。在 onPreResponse
方法中,我们将响应异常转换为自定义异常类型,然后在返回时将响应转换为自定义异常响应。在路由中,我们将抛出一个 BadRequestError
类型的错误,其中指定了错误码('40001'
),然后将该错误响应抛出。
该方案的优点是能够提高代码的可读性和可维护性,同时也可以进行统一的异常处理。
使用插件进行异常处理
除了在代码中实现自定义异常处理外,Hapi.js 还提供了一种更加灵活的异常处理方式,即使用插件进行异常处理。该方式的优点是可以将异常处理逻辑独立出来,不与业务代码耦合,方便插件的可复用性。
以下是一个简单的插件实现示例:
// javascriptcn.com 代码示例 const HttpError = require('./lib/http-error'); exports.plugin = { name: 'error-handler', version: '1.0.0', register: function(server, options) { server.ext('onPreResponse', function(request, h) { const { response } = request; if (!response.isBoom) { return response; } const { output } = response; const { res, payload } = output; const error = { code: payload.code || res.statusCode, message: payload.message || payload.error, }; return h.response({ error }).code(res.statusCode); }); // 抛出一个通用的异常实例 server.decorate('toolkit', 'throw', function(statusCode, message, code) { throw new HttpError(statusCode, message, code); }); // 抛出一个参数错误类型的异常实例 server.decorate('toolkit', 'badRequest', function(message, code) { throw new HttpError(400, message, code); }); } };
在上面的代码中,我们定义了一个 error-handler
插件,并在其中实现了自定义异常处理逻辑。在插件的 register
方法中,我们使用 server.ext
方法注册 onPreResponse
方法,然后在该方法中进行异常处理。在 toolkit
对象中,我们通过 server.decorate
方法定义了两个方法 throw
和 badRequest
,分别用于抛出通用异常类型和参数错误异常类型。这样,在业务代码中我们就可以方便地抛出异常了。
// javascriptcn.com 代码示例 server.register({ plugin: require('./plugins/error-handler') }); server.route({ method: 'GET', path: '/users', handler: async function(request, h) { h.badRequest('参数错误', '40001'); } }); server.start();
在上述代码中,我们使用 server.register
方法注册了 error-handler
插件,然后在路由的业务处理代码中,通过调用 h.badRequest
方法抛出一个参数错误异常。
总结
本文介绍了 Hapi.js 中实现自定义异常处理的技巧和优化方案。通过自定义异常处理,我们可以对异常信息进行更细粒度的控制和优化,提高 API 服务的可读性和可维护性。在实际开发中,建议使用插件进行异常处理,方便进行异常处理逻辑的复用。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6531ca467d4982a6eb3b9a05