API 的错误响应也需要设计
失败不仅是一句“请重试”。区分无效输入、额度用完、服务中断和生成失败,让前端知道能做什么,也让错误响应守住数据边界。
向下阅读
设计一个接口时,成功响应往往最早被确定:有哪些字段,怎么展示,怎样进入下一步。错误却容易被压缩成一段兜底文本,直到前端需要处理各种失败,才发现它们并不是同一种情况。
一个站内问答请求可能因为输入无效而被拒绝,也可能因为额度已用完、外部服务暂时不可用或回答没有完整生成而失败。用户能采取的行动不同,接口提供的信息也应该不同。
错误先说明还能做什么
输入过长,用户可以缩短问题;提问过快,可以等待;当天额度用完,需要等到重置;服务连接中断,则可以稍后重试。把它们全部显示成“发生错误”,会让恢复路径失去方向。
接口不一定需要暴露内部分类的全部细节,但应该提供前端能够可靠使用的语义。剩余额度、重置时间和必要的重试等待信息,都是对用户决策有帮助的数据。
这些信息也需要保持一致。失败请求如果仍计入额度,界面就不能因为没有答案而保留旧次数。成功与失败都应该更新同一份真实计数,而不是分别维护看起来更乐观的数字。
对外文本不能照搬内部错误
外部服务返回的错误可能包含请求细节,内部异常也可能带上路径、配置或其他不适合公开的内容。把异常对象直接序列化给浏览器,会把调试信息与用户说明混在一起。
可以在服务端区分内部原因与对外消息。用户需要知道连接失败、稍后可重试,不需要看到模型密钥、原始请求正文或服务内部堆栈。对外消息应由本站控制,不能因为更换了服务商就突然展示另一套未检查的字段。
这并不意味着把所有问题隐藏起来。真正需要排查的原因可以通过适当的服务端观测保留,但应另行决定记录哪些内容。浏览器响应不是日志文件,日志也不应该成为无限保存个人问题的理由。
开始响应之后还有失败
普通请求可以在生成最终结果之前决定返回什么状态。流式请求不同:响应已经开始、文字已经出现,后面仍可能发生错误。此时不能假装重新发出一份完全不同的普通响应。
把错误作为流内的明确事件,前端就能停止预览、显示说明,并决定保留哪些状态。完成与错误需要是不同的结果;如果只是连接关闭,客户端还应判断有没有收到正常完成信号。
客户端处理这些事件时,也不能只看有没有文字。半段内容可能读起来很合理,但仍然缺少结尾或有效来源。可读性与请求是否完成,需要分别判断。
让错误分支成为接口的一部分
一个完整的接口说明,应该包括无效输入、未启用、额度限制、上游失败和中断等分支。这样前端在实现状态时,不必根据偶然出现的错误文案猜测行为。
错误文案可以变得更友好,语义却应该稳定。修改一句提示,不应该意外改变是否允许重试或是否扣除额度。字段、状态和显示文字分别承担职责,会让这类修改更安全。
成功响应告诉用户系统能完成什么,错误响应告诉用户遇到边界时还能怎样继续。把后一半也认真设计,接口才算真正支持了一条完整的使用路径。