跳到主要内容

4. 定义新的问题类型

当 HTTP API 需要定义一个表示错误条件的响应时, 通过定义新的问题类型来做到这一点可能是合适的.

在这样做之前, 重要的是理解它们适合做什么, 以及哪些内容最好留给其他机制处理.

问题详情不是底层实现的调试工具; 相反, 它们是一种公开 HTTP 接口自身更多细节的方式. 新问题类型的设计者需要仔细考虑安全考虑事项 (第 5 节), 特别是通过错误消息暴露实现内部细节从而暴露攻击向量的风险.

同样, 真正通用的问题 -- 即可能适用于 Web 上任何资源的条件 -- 通常最好用普通状态码表达. 例如, "不允许写访问" 问题可能没有必要, 因为对 PUT 请求返回 403 Forbidden 状态码已经不言自明.

最后, 应用可能已经定义了更适合承载错误的格式. 问题详情旨在避免建立新的 "fault" 或 "error" 文档格式的必要性, 而不是替代现有的领域专用格式.

也就是说, 可以使用 HTTP 内容协商将问题详情支持添加到现有 HTTP API 中 (例如使用 Accept 请求头表示对此格式的偏好; 见 [RFC7231] 第 5.3.2 节).

新的问题类型定义必须记录:

  1. 一个类型 URI (通常使用 "http" 或 "https" 方案),

  2. 一个能恰当描述它的标题 (应保持简短), 以及

  3. 与其一起使用的 HTTP 状态码.

问题类型定义可以规定在适当情况下使用 Retry-After 响应头 ([RFC7231] 第 7.1.3 节).

问题的类型 URI 应当解析到 HTML [W3C.REC-html5-20141028] 文档, 说明如何解决该问题.

问题类型定义可以在问题详情对象上规定附加成员. 例如, 扩展可以使用类型化链接 [RFC5988] 指向另一个资源, 机器可使用该资源解决问题.

如果定义了这些附加成员, 其名称应当以字母开头 (ALPHA, 见 [RFC5234] 附录 B.1), 并且应当由 ALPHA、DIGIT ([RFC5234] 附录 B.1) 和 "_" 中的字符组成 (这样它可以序列化为 JSON 以外的格式), 且长度应当为三个或更多字符.

4.1. 示例

例如, 如果你发布一个面向在线购物车的 HTTP API, 可能需要表示用户余额不足 (即上面的示例), 因而无法完成购买.

如果已经有能够容纳此信息的应用专用格式, 通常最好使用该格式. 但是, 如果没有, 可以考虑使用问题详情格式之一 -- 如果 API 基于 JSON, 则使用 JSON; 如果使用 XML, 则使用 XML.

为此, 可以寻找一个已经定义且符合目的的类型 URI. 如果存在, 可以复用该 URI.

如果不存在, 可以铸造并记录一个新的类型 URI (它应当在你的控制之下并随时间保持稳定)、一个合适标题以及将与之一起使用的 HTTP 状态码, 并说明其含义以及应如何处理.

总之: 实例 URI 总是标识某个问题的具体发生实例. 另一方面, 如果某处已经有合适的问题类型描述, 类型 URI 可以复用; 也可以为新的问题类型创建类型 URI.

4.2. 预定义问题类型

本规范保留一个 URI 作为问题类型:

当 "about:blank" URI [RFC6694] 被用作问题类型时, 表示该问题除了 HTTP 状态码的语义之外没有其他附加语义.

使用 "about:blank" 时, title 应当与该状态码的推荐 HTTP 状态短语相同 (例如 404 对应 "Not Found" 等), 但可以根据客户端偏好进行本地化 (通过 Accept-Language 请求头表达).

请注意, 根据 "type" 成员的定义方式 (第 3.1 节), "about:blank" URI 是该成员的默认值. 因此, 任何未携带显式 "type" 成员的问题详情对象都会隐式使用该 URI.