GraphQL 是一种新兴的查询语言,越来越多的公司将其应用于生产环境中。GraphQL 具有很好的灵活性和可扩展性,但是由于它的复杂性,错误处理极为重要。在本文中,我们将探讨 GraphQL 错误处理的方式,以及如何在软件开发中恰当地处理错误。
GraphQL 错误处理
GraphQL 查询可以返回两种类型的结果:数据和错误。因此,GraphQL 系统在处理查询时需要更多的错误处理机制。以下是一些 GraphQL 错误的例子:
- 语法错误
- 数据源错误
- 解析错误
- 缓存错误
- 认证和授权错误
对于每一种错误类型,GraphQL 都会返回一个包含详细错误信息的错误对象。例如,以下是一个包含 GraphQL 语法错误的查询:
{ user(id: 123 { name } }
当这个查询被执行时,GraphQL 会返回以下错误对象:
-- -------------------- ---- ------- - ---------- ------- ------ -------- --- ----- ----- ------------ - - ------- -- --------- -- - - -
在这个错误对象中,"message" 代表错误信息,"locations" 代表错误发生的位置。
为了更好地处理 GraphQL 错误,我们需要让错误信息更加准确,同时确保在最终用户看来这些错误信息可以理解。例如,在上面的例子中,我们不仅需要知道错误的位置,还需要知道错误的原因。因此,以下是我们可以改进的错误对象:
-- -------------------- ---- ------- - ---------- ------- ------ -------- --- ----- --- ----- ------- ------ ------- ------------ - - ------- -- --------- -- - -- ------- - ------ - -
在这个错误对象中,"path" 代表查询路径。
错误处理的最佳实践
捕捉错误
使用 try-catch 捕捉错误是从语法级别保护我们的代码的一种标准做法,但需要确保我们捕捉到的错误是我们期望捕捉到的。
function getUser(id) { try { const user = db.getUserById(id); return user; } catch (error) { return null; } }
在这个示例中,我们正在执行某些从数据库中获取数据的代码。在成功的情况下,我们返回用户数据,否则返回 null。但是,如果有一个 SQL 错误被触发,我们不能简单地返回 null,并再试一次!因此,以下是我们可以改进的代码:
function getUser(id) { try { const user = db.getUserById(id); return user; } catch (error) { throw new Error(`Failed to get user ${id}. ${error}`); } }
在这个示例中,我们仍然使用 try-catch 捕捉错误,但是不返回 null,而是使用 throw 语句来抛出一个新的错误对象,其中包含原始错误信息。这样,在返回结果之前,我们可以更仔细地检查这个错误。
统一错误处理
在 GraphQL 中,我们需要为错误对象提供一种统一的处理方式。这意味着我们需要确保我们向终端用户返回的所有错误包含以下信息:
- 错误信息
- 错误码
- 错误类型
- 错误原因
以下是我们可以使用的错误对象:
{ "message": "Unable to process request", "code": 500, "type": "Server Error", "reason": "Application crashed due to an unexpected exception." }
在这个错误对象中,"message" 代表错误信息,"code" 代表错误码(例如 500 代表服务器错误),"type" 代表错误类型(例如 "Server Error"),"reason" 代表错误原因。这种错误对象可以帮助用户快速理解问题的性质。
缓存错误
缓存是一个非常有用的技术,但是如果缓存被错误使用,它可能导致整个系统的崩溃。因此,在使用缓存时,我们需要考虑以下几个因素:
- 缓存时间:缓存应该在多长时间内有效?
- 缓存清除:缓存应该何时被清除?
- 缓存失败:如果缓存失败,我们该怎么做?
以下是一个使用 Redis 缓存用户数据的示例:
-- -------------------- ---- ------- ----- ----- - ----------------- ----- ------ - --------------------- -------- ----------- - ------ --- ----------------- ------- -- - ------------------------ ------- ------- -- - -- ------- - -------------- - ---- -- -------- - ---------------------------- - ---- - ----- ---- - ------------------- ------------------------ --------------------- -- -- - --------------------------- ---- --- -------------- - --- --- -
在这个示例中,我们正在使用 Redis 缓存用户数据。在第一次调用 getUser() 之后,我们将结果缓存到 Redis,并设置过期时间为 60 秒。这意味着在 60 秒内,所有对 getUser() 的后续调用都将返回相同的结果,而不需要再从数据库中读取数据,从而提高了性能。
但是,如果我们在缓存失败的情况下不处理错误,那么我们在缓存失败的情况下就需要从数据库中读取数据。这可能会导致过多的数据库连接请求,并且可能导致系统崩溃。因此,以下是我们可以改进的代码:
-- -------------------- ---- ------- ----- ----- - ----------------- ----- ------ - --------------------- -------- ----------- - ------ --- ----------------- ------- -- - ------------------------ ------- ------- -- - -- ------- - -------------- - ---- -- -------- - ---------------------------- - ---- - ----- ---- - ------------------- -- ------- - ---------- ----------- ----- --- --------- - ---- - ------------------------ --------------------- -- -- - --------------------------- ---- --- -------------- - - --- --- -
在这个示例中,我们确保在从数据库中获取数据时没有错误,在缓存对象时也没有错误。如果有任何错误发生,我们都会使用 reject() 函数返回一个错误对象。
日志
日志是调试和排除错误的重要工具。在 GraphQL 中,我们需要将每次查询和错误都记录下来,以便将来可以更轻松地为服务器问题和错误做出响应。以下是我们可以使用的日志对象:
-- -------------------- ---- ------- - ------------ ----------- -------- -------- ---------- ------- -- --- ---- ----- -- ---- ----- ---- ---- ----- ------- ------- ------- -------------- --- ------------- ------------ ----- ----------- --------- -------------- ---------- - - ------ --------- -------- ------ - - -
在这个日志对象中,我们记录了时间戳,日志级别(例如 error),错误信息,错误类型,应用程序名称,组件名称,方法名称以及细节(例如查询路径)。
结论
错误处理是软件开发中的一个关键方面。对于 GraphQL 系统,我们需要确保我们的错误处理方案能够捕捉到所有错误,并提供易于读取和理解的错误对象。我们还需要确保我们的缓存和日志方案都是健壮和可扩展的。当我们设计和实现 GraphQL 系统时,我们需要在每个步骤中考虑错误处理,以确保我们的应用程序代码能够在面对不可避免的问题时保持强壮、灵活和可靠。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/674e85dfe884a3e30f27e826