4. 定义新的问题类型
当 HTTP API 需要定义一个表示错误条件的响应时, 通过定义新的问题类型来做到这一点可能是合适的.
在这样做之前, 重要的是理解它们适合做什么, 以及哪些内容最好留给其他机制处理.
问题详情不是底层实现的调试工具; 相反, 它们是一种公开 HTTP 接口自身更多细节的方式. 新问题类型的设计者需要仔细考虑安全考虑事项 (第 5 节), 特别是通过错误消息暴露实现内部细节从而暴露攻击向量的风险.
同样, 真正通用的问题 -- 即可能适用于 Web 上任何资源的条件 -- 通常最好用普通状态码表达. 例如, "不允许写访问" 问题可能没有必要, 因为对 PUT 请求返回 403 Forbidden 状态码已经不言自明.
最后, 应用可能已经定义了更适合承载错误的格式. 问题详情旨在避免建立新的 "fault" 或 "error" 文档格式的必要性, 而不是替代现有的领域专用格式.
也就是说, 可以使用 HTTP 内容协商将问题详情支持添加到现有 HTTP API 中 (例如使用 Accept 请求头表示对此格式的偏好; 见 [RFC7231] 第 5.3.2 节).
新的问题类型定义必须记录:
-
一个类型 URI (通常使用 "
http" 或 "https" 方案), -
一个能恰当描述它的标题 (应保持简短), 以及
-
与其一起使用的 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.