前言
GraphQL 是一种用于 API 接口的查询语言,它让前端可以只请求自己需要的数据,而避免了 RESTful API 那样返回大量冗余的数据。
然而,真正利用好 GraphQL 也需要一定技巧。本文将阐述在使用 GraphQL 时,错误处理的相关问题,包括大致流和客户端缓存不一致等问题,并提供相应解决方案和示例代码。希望本文能对理解 GraphQL 以及前端开发有所启发。
背景
在使用 GraphQL 时,我们会通过发送一个长长的查询语句获取所需数据。正常情况下,后端会返回客户端所需的数据。但如果没有处理好错误情况,则可能出现以下问题:
大致流
大致流(inexact flow)指的是,客户端在获取数据时,数据状态(例如数据是否加载完毕、是否有错误等)与实际有出入。例如,在完成某个任务之前,客户端已经收到了一部分的数据并进行了数据展示,但实际上这些数据只是一个中间状态,会在后续的操作中进行处理。
如上图所示,客户端直接从服务端获取到了查询结果中的一部分,这时候客户端并没有意识到数据未加载完毕,渲染了未完成的内容。
客户端缓存不一致
GraphQL常常会引入客户端缓存,以优化应用性能。但如果不加以限制,就会导致客户端与服务端的数据不一致,令用户看到不正确或不完整的数据。
如上图所示,客户端在接收到服务端数据后,将数据缓存在本地客户端,然后用户操作触发新的查询(例如筛选),客户端经过本地缓存直接返回数据,但其实服务端的数据已经更新了,导致返回的数据不一致。
解决方案
为解决大致流和客户端缓存不一致问题,我们需要在GraphQL API 的错误处理上下功夫。具体实现有以下方案:
1. 通过错误码区分不同错误
GraphQL 应用中,通常会定义不同的错误码,针对不同的错误返回特殊的错误信息。例如,HTTP 中的 404 就是一种常用的错误码。
在 GraphQL 中,我们可以通过定义一套自己的错误码进行处理:
-- -------------------- ---- ------- ---- ----- - -------- ----- ---- - ---- ---- - --- --- ------ ------- ----- ------- -------- ------ ------------ -------- - ---- --------- - -------------- - ---- ---------- - ----- ---------- - ----- ----------- - ---------- - ----
这里我们自定义了一个错误码 ErrorCode
,来区分不同的错误。错误信息会以 QueryError
类型返回,客户端可以根据错误码来判断错误类型并进行不同处理。
2. 通过 errors
字段返回多个错误
在 GraphQL API 中,如果出现多个错误,则使用 errors
字段返回。 errors
是一个包含多个错误对象的列表,每个错误对象都有一个描述信息和错误码。
-- -------------------- ---- ------- ---- ----- - -------- ----- ---- - ---- ---- - --- --- ------ ------- ----- ------- -------- ------ ------------ -------- - ---- ---------- - ----- ---------- - ----- ----------- - ---------- - ---- ---- ------------- - ------- ----------- ------- -------------- -
这里我们定义了一个新类型 QueryResponse
,用于包装 result
和 errors
信息,并以此来统一返回数据和错误信息。
3. 通过 response.extensions
传递额外信息
为避免客户端缓存造成数据不一致,我们可以借鉴 HTTP 缓存控制的做法,通过 Cache-Control
头部设置缓存控制策略,或者通过响应头部返回 ETag
或者 Last-Modified
等信息,来避免客户端缓存不一致情况的出现。
在 GraphQL 中,可以使用 extensions
返回一些额外的信息。其中,cacheControl
字段可以用于设置客户端缓存策略。
-- -------------------- ---- ------- ---- ----- - -------- ----- ---- - ---- ---- - --- --- ------ ------- ----- ------- -------- ------ ------------ -------- - ---- ---------- - ----- ---------- - ----- ----------- - ---------- - ---- ---- ------------- - ------- ----------- ------- -------------- - ---- ------------ - --------- -------------- ----------- ---------------- - ---- --------------- - ------------- ------------- - ---- ------------ - ------- ---- -
在上面的示例中,我们定义了一个新的类型 QueryPayload
用于包装响应数据以及缓存相关信息。 QueryExtensions
中新增了一个 cacheControl
字段,用于表示缓存控制信息。CacheControl
中的 maxAge
字段则决定了客户端如何缓存数据。
示例代码
-- -------------------- ---- ------- ---- ----- - -------- ----- ---- - ---- ---- - --- --- ------ ------- ----- ------- -------- ------ ------------ -------- - ---- --------- - -------------- - ---- ---------- - ----- ---------- - ----- ----------- - ---------- - ---- ---- ------------- - ------- ----------- ------- -------------- - ---- ------------ - ------- ---- - ---- --------------- - ------------- ------------- - ---- ------------ - --------- -------------- ----------- ---------------- - ---- ----- - -------- ----- ------------- - ------ - ------ ----- -
在上面的示例代码中,我们通过定义 QueryPayload
,并在 Query
中返回该类型,以便包装缓存信息和错误信息,并避免无意间缓存客户端数据导致不一致的问题。
-- -------------------- ---- ------- ------ - ------- - ---- ----------------- --------- ---- - --- ------ ------ ------ ------ ------ --------- ------ ------------- -------- - --------- ---------- - ----- ------ - --------- ----------- - -------- ---- -------- ------------ - --------- ------------- - ----- ----------- ------------ - ------------- - ------- ------ - - - ----- --------- - ----- ---- -------- -------------------- -- - ----- ----- - - ----- ----- ---- - -------- ---- - -------- - ------ - -- ----- ---- ------- ----------- - - ------ - ---- - ---------- - ------------ - ------ - - - - - ----- --------- - - --- - ----- -------- - ----- ---------------------------------- ------ ---------- ------ ------------- - ----- ------ - ----- ---------------- ----- - ------- ----- ------ - - ------ -- ------ - -- -- --------- - ---- -- --------------- - -- ------ ------ -
在上面的示例代码中,我们使用 graphql-request
来发送 GraphQL 查询请求,并解析响应中的数据以及错误信息。同时,也获取了返回的缓存信息。
结论
本文详细阐述了 GraphQL 错误处理的相关问题,并提供了相应的解决方案和示例代码。希望这篇文章能够对前端开发人员在使用 GraphQL 时,解决大致流和客户端缓存不一致问题,有所启发。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6749b6d6a1ce0063546dd52d