错误处理
GraphQL 中的错误处理
查询执行过程中从不抛出异常。相反,所有的错误都会被捕获和收集起来。
执行结束后,它们可以在 GraphQL\Executor\ExecutionResult
的 $errors 变量中找到。
当使用其 toArray() 方法将返回结果转换为可序列化的数组时,所有的错误都会使用默认的错误格式(见下面)并转换为数组。
或者,你可以使用 自定义的错误过滤和格式设置 来满足你的个性化需求。
默认错误格式
默认情况下,每一个错误记录都会转换为具有以下结构的关联数组:
<?php
[
'message' => 'Error message',
'category' => 'graphql',
'locations' => [
['line' => 1, 'column' => 2]
],
'path' => [
'listField',
0,
'fieldWithException'
]
];
记录中的 locations 字段指向的是在查询字符串中导致错误的字符。
在某些情况(像深层次的分片字段)下,locations
将包含多条记录以便于追踪在查询中出现错误的字段路径。
记录中的 path 字段仅存在于解析器抛出的异常引起错误时。
它包含根字段到产生错误的真实字段的路径(包括列表类型的索引和复合类型的字段名)。
内部错误
从 0.10.0 版本开始,解析器抛出的所有异常都会使用通用信息 「Internal server error」 进行报告。
这样做是为了避免生产环境中的信息泄露(比如数据库连接错误、文件访问错误等)。
只有实现了接口 GraphQL\Error\ClientAware
并声明自身是 安全 的异常才会报告一个完整的错误信息。
例如:
<?php
use GraphQL\Error\ClientAware;
class MySafeException extends \Exception implements ClientAware
{
public function isClientSafe()
{
return true;
}
public function getCategory()
{
return 'businessLogic';
}
}
当抛出这样的异常时,才会报告一个完整的错误信息:
<?php
[
'message' => 'My reported error',
'category' => 'businessLogic',
'locations' => [
['line' => 10, 'column' => 2]
],
'path' => [
'path',
'to',
'fieldWithException'
]
];
要将默认的 「Internal server error」 信息修改为其他内容时,请使用:
GraphQL\Error\FormattedError::setInternalErrorMessage("Unexpected error");
调试工具
在开发或调试期间,使用 $result->toArray(true)
将 debugMessage 字段添加到每个格式化的错误记录中。如果你还想添加异常追踪 - 传递标志,而不是:
use GraphQL\Error\Debug;
$debug = Debug::INCLUDE_DEBUG_MESSAGE | Debug::INCLUDE_TRACE;
$result = GraphQL::executeQuery(/*参数*/)->toArray($debug);
那么,每个错误记录看起来像这样:
<?php
[
'debugMessage' => 'Actual exception message',
'message' => 'Internal server error',
'category' => 'internal',
'locations' => [
['line' => 10, 'column' => 2]
],
'path' => [
'listField',
0,
'fieldWithException'
],
'trace' => [
/* 格式化的原始错误堆栈 */
]
];
如果你希望重新抛出第一个解析器的异常,请使用下面的标志:
<?php
use GraphQL\GraphQL;
use GraphQL\Error\Debug;
$debug = Debug::INCLUDE_DEBUG_MESSAGE | Debug::RETHROW_INTERNAL_EXCEPTIONS;
// 下面代码会在解析器执行过程中抛出异常
$result = GraphQL::executeQuery(/*参数*/)->toArray($debug);
自定义错误处理及格式
可以为结果中的错误自定义 格式化程序 和 处理程序。
格式化程序 负责将 GraphQL\Error\Error
实例转换为一个数组。处理程序 对错误过滤和日志记录非常有用。
例如,这些是默认的格式化程序和处理程序:
<?php
use GraphQL\GraphQL;
use GraphQL\Error\Error;
use GraphQL\Error\FormattedError;
$myErrorFormatter = function(Error $error) {
return FormattedError::createFromException($error);
};
$myErrorHandler = function(array $errors, callable $formatter) {
return array_map($formatter, $errors);
};
$result = GraphQL::executeQuery(/* $args */)
->setErrorFormatter($myErrorFormatter)
->setErrorsHandler($myErrorHandler)
->toArray();
请注意,当你通过 调试标记 使用 toArray() 时,你的自定义格式仍然会使用上面提到的调试信息来进行装饰。
Schema 错误
到目前为止,我们仅仅覆盖了发生在查询过程中的错误。但如果其中一个类型定义有错误,Schema 也会抛出 GraphQL\Error\InvariantViolation
的异常。
通常这样的错误意味着在你的 Schema 中有逻辑错误,而且,这也是 GraphQL 端点返回错误码 500
的唯一情况:
<?php
use GraphQL\GraphQL;
use GraphQL\Type\Schema;
use GraphQL\Error\FormattedError;
try {
$schema = new Schema([
// ...
]);
$body = GraphQL::executeQuery($schema, $query);
$status = 200;
} catch(\Exception $e) {
$body = [
'errors' => [FormattedError::createFromException($e)]
];
$status = 500;
}
header('Content-Type: application/json', true, $status);
echo json_encode($body);
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。