Dev KnowledgeV2.0
输入关键词开始搜索

    流式请求的错误提示与安全降级

    将 fetch()、HTTP 与流读取错误统一成稳定提示,并安全地建议切换备用资源。

    类型
    操作指南
    适合读者
    正在实现流式请求、错误协议和备用资源切换的前端开发者
    最近核验

    流式请求可能在三个阶段失败:建立连接前的 fetch() 异常、HTTP 非成功响应,以及已经开始读取后的流中断。这三类错误必须统一进入可测试的错误协议,不能把浏览器产生的 Failed to fetch 等原始文案直接展示给用户。

    统一错误码

    网络层应该保留用户主动取消,同时把其他连接与读取异常归一化:

    const signal = options.signal
    
    try {
      const response = await fetch(url, options)
      if (!response.ok) throw await parseStructuredError(response)
      if (!response.body) {
        throw new AppError('响应不包含可读数据流', 'INVALID_STREAM')
      }
      await consumeStream(response.body)
    } catch (error) {
      if (signal?.aborted) throw error
      if (error instanceof AppError) throw error
      throw new AppError('服务连接中断', 'NETWORK_ERROR')
    }

    检查 signal.aborted 而不只匹配 AbortError 名称,可以保留 abort(reason) 传入的自定义取消原因。Response.body 的类型允许为 null,流式端点还应把“成功状态但没有流”归为独立协议错误。界面层只根据稳定的 code 映射可读原因,例如网络中断、限频、额度不足、上游不可用、超时、上下文过长和鉴权失败。后端返回的结构化错误码应原样保留;浏览器或代理的实现细节不应成为用户文案。相关底层语义见 Fetch Standard

    明确失败对象与备用项

    如果请求可能在服务端被路由到备用资源,界面需要分别记录:

    • 用户发起请求时选择的资源。
    • 流中已经确认的实际资源。

    错误发生在解析实际资源之前时,提示所选资源;之后发生时,提示实际资源。备用建议应来自同一批服务端发布的可用列表,从失败位置向后查找,跳过冷却或禁用项,并允许从列表末尾回绕。

    只有资源相关错误才建议切换。上下文过长、内容拒绝、鉴权失败或本地持久化失败不能通过切换资源解决,不应显示误导性的切换按钮。

    不要盲目自动重试流式 POST

    连接在客户端看来失败时,服务端可能已经完成生成或持久化。自动重放非幂等 POST 可能造成重复消息、重复扣费或重复副作用。更安全的默认交互是:

    1. 明确显示失败资源与可读原因。
    2. 提供一键切换到建议资源。
    3. 由用户确认后重新发送。

    真正需要自动重试时,应先为请求增加稳定的幂等键,并让服务端能够查询、复用或拒绝重复请求。

    验证

    至少覆盖以下测试:

    • fetch() 直接拒绝时不泄漏浏览器原始文案。
    • HTTP 非成功响应保留后端结构化错误码。
    • 流读取中断映射为同一个网络错误码。
    • 备用选择跳过冷却项并能回绕。
    • 鉴权、上下文等非资源错误不提供切换建议。
    • 用户主动取消不会显示成服务故障。

    这套边界可通过聚焦单元测试验证错误映射与备用选择,再用真实流式接口验证首包、降级解析和连接中断行为。