RFC-0060:错误处理 | |
---|---|
状态 | 已接受 |
领域 |
|
说明 | API 通常需要指明请求无法成功完成。通常包含与错误相关的实用上下文信息,可让调用方采取纠正措施。它提出了一种语法,使 FIDL 接口能够描述如何报告错误。 |
作者 | |
提交日期(年-月-日) | 2018-09-18 |
审核日期(年-月-日) | 2018-12-06 |
摘要
API 通常需要指明请求无法成功完成。 通常,系统会参考一些有用的上下文信息, 可让来电者采取纠正措施。 它提出了一种语法,使 FIDL 接口能够描述错误的 遭到举报。
设计初衷
大多数编程语言都提供错误处理结构,如异常、
Future/Promise、结果类型或错误类型。
使用不具有相应功能的语言编写的 API 通常会自行制定惯例
例如 errno
、zx_status_t
和 GError
。
FIDL 方法可以返回多个值,因此方法可能会同时返回一个值,
错误代码,但这是以不一致的临时方式完成的。
通常,接口作者会把错误代码放在方法前面
但大约有 20% 的情况是相反的
有时,接口会返回 struct
,其中包含状态代码和
结果。
状态表示为 bool
、int
、enum
、string
和 struct
。
API 的这种多样性对于开发者来说很难理解。 缺少显式语法,无法区分方法结果与错误 信息使无法生成惯用的绑定。
设计
我们应该扩展 FIDL 方法语法,以便接口能够描述 不同的 result 返回类型和 error 返回类型。 事件从不具有错误类型。 语法如下所示:
interface Example {
// This method returns no values, failures or completion.
1: NoReturn();
// This method returns no values or failures but informs
// clients of completion.
2: Completion() -> ();
// This method returns a single value.
3: SingleValue() -> (int32 result);
// This method returns multiple values.
4: MultipleValue() -> (int32 foo, string bar);
// This method doesn't return any values but can indicate a
// failure reason.
5: CanFail() -> () error int32;
// This method can succeed with a result or fail with a reason.
6: WinOrLose() -> (string result) error ExampleError;
};
未声明错误类型的方法会被序列化,并严格按照
发展到了如今
返回参数编码为 FIDL struct
。
会声明错误类型的方法会被序列化为 结果和错误返回值类型。 因此,像下面这样的方法:
interface Example {
1: Method() -> (string result, string other_result) error int32;
};
其编码如下所示:
struct ExampleMethodResult {
string result;
string other_result;
};
[Result]
union ExampleMethodReturn {
ExampleMethodResult result;
int32 err;
};
interface Example {
1: Method() -> (ExampleMethodReturn return);
};
错误类型必须是 int32
、uint32
或其中一种类型的 enum
。
尽管理想情况下,所有现有接口都将与源接口和二进制文件兼容 它们会不断演变,使用新的错误语法。
在 FIDL IR 中,表示结果或错误的并集将加以区分
因为前端编译器会附加 [Result]
属性。
现有的语言绑定将继续有效,但可以更新以支持
更多惯用语言功能,用于表示失败的方法调用。
我们提议 Dart 通过 Future
错误返回失败结果。
它们应该是 package:fidl
中定义的特殊 Error
类型的子类
以便轻松区分应用级错误与绑定
以及协议错误
Rust 应使用 std::result::Result
。
如果 std::expected
变成现实,但是在
在此期间,我们可以对该提案进行充分的实施,以满足
FIDL。
Go 绑定应为错误返回使用自定义错误类型。
实施策略
这可以通过以下步骤实现:
- 更新
fidlc
以支持新语法。 - 检查它定义的编码是否正确。
- 更新了 FIDL 语言文档。
- 更新绑定以使用更惯用的错误处理方式。
- 更新 FIDL 兼容性测试接口 来测试错误并添加对所有语言绑定的支持。
- 验证语言绑定是否正确可互操作。
- 更新文档。
- 鼓励接口作者改进接口以使用错误 返回值类型。
文档和示例
这是对 FIDL 的重大更改。 语言和电汇格式文档必须更新为 介绍新语法及其序列化方式。 FIDL 教程应进行更新,以提供有关如何 正确返回 需要更新 API 方法评分准则,以说明适当的用法 功能部分。
向后兼容性
大多数现有的 FIDL 接口仍将与此变更兼容。
唯一的重大更改是 error
成为了保留字。
性能
性能影响应该非常小。
安全
标准化错误报告语义将简化调用 FIDL 的代码 方法。 明确要优于隐式。
测试
这将需要进行 fidlc
测试、兼容性测试,可能还需要语言测试
绑定特定的测试,以确保绑定符合惯例。
缺点、替代方案和未知问题
这会给语言增加一些复杂性,但这种复杂性只是描述 我们接口中已隐式表示的语义。
此提案不包含的一个建议是制定一个
error 枚举,描述错误类别并在
如何继续操作。
此模式在 errno
、zx_status_t
和 HTTP 状态中很常见
代码。
这些示例会试图捕捉到比我们认为合适的更多细节。
对我们来说,grpc_status_code
是一个更好的模型,
高级别的错误
我们正在考虑向标准 FIDL 库中添加通用错误枚举,
接口作者可以选择使用,而不是自己开创。
针对如何折叠应用错误(例如, 出现传输级别 FIDL 错误(例如,邮件解析失败)。 目前,所有传输级别 FIDL 错误都会导致通道关闭,因此 也无需折叠任何错误代码 我们希望能够从此类错误中恢复,但 在未来的 FTP 中提议。 将错误保持在 32 位以内留出很多机会进行错误折叠。
此方案的早期版本允许将错误属于任意数据类型。 这可能会鼓励反面模式,例如返回错误消息字符串 会限制我们的灵活性,因为我们会努力使错误与书信保持一致 重新检查错误折叠 目前,我们采用更为保守的误差表示方法。
先验技术和参考资料
- GRPC 会随每个结果返回一个状态代码
- DBus 方法调用会返回结果数据或错误对象
- 所有 COM 调用都会返回 HRESULTS 代码
- Binder 状态包括标准错误代码以及特定于应用的代码 和字符串