错误处理

未匹配的标注

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);

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/graphql-php/err...

译文地址:https://learnku.com/docs/graphql-php/err...

上一篇 下一篇
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
贡献者:2