空数组不是请求状态
列表页把数据初始值设为空数组很方便,但如果视图只检查长度,就会把尚未开始、正在请求、成功返回空集合和失败后没有数据四个事实混成“暂无数据”。请求状态必须是独立信号,而数据只是成功分支携带的载荷。空态只能从“已成功且集合长度为零”推导,绝不应从默认值推导。
可以把页面状态建模为空闲、首次加载、已成功、刷新中和失败,其中成功再根据数据量派生有内容或空集合。刷新中与首次加载不同:前者可以保留上一份成功数据并标记正在更新,后者没有可信的旧内容。这种区分能避免用户每次翻页或手动刷新时都看到整页闪烁,同时不会把旧值冒充新请求的成功。
状态推导应集中在一个纯函数或计算属性中,输入仅为请求状态、数据和错误,输出为互斥的视图分支。不要在模板多处分别组合真假条件,否则可能同时出现骨架和空态,或错误提示被旧列表遮住。为推导函数写表驱动测试,把这些组合当成业务契约,比只做页面截图更能防止回归。
Nuxt 请求对象与视图状态的对应
Nuxt 的数据获取组合式接口会暴露数据、错误和状态等响应式值,页面应基于这些原始信号派生界面,而不在捕获异常后手工把数据重置为空。对首次加载用显式骨架或状态文字,对成功空集合给出与当前筛选相关的空态,对失败则保留错误类型与可执行操作。数据默认值可以方便模板迭代,但不能参与判定请求是否成功。
同一个页面常包含主列表、统计卡和筛选选项等多个请求。不要用一个全局加载布尔值表示所有请求,它会在任一请求完成时过早关闭,也无法告诉用户哪一块失败。每个资源保持自己的请求状态,页面级状态再按依赖关系聚合:主列表失败可能阻断页面,一张辅助卡失败则只需局部重试。这样才能在不隐藏故障的前提下保留可用内容。
请求键是缓存与共享状态的身份,应包含会改变结果的页码、筛选、排序、语言与权限作用域。两个组件使用同一键时,对默认值、转换函数、数据抽取和深层响应式等关键选项应保持一致,否则它们会共享同一份内部状态却对其形状有不同假设。为键建立小型工厂函数,可减少字符串拼接遗漏参数造成的串数据。
鉴权错误是会话边界而非空集合
未登录或会话失效的管理请求应返回未授权,客户端清理本地会话视图并跳转登录页,同时保留安全的返回地址。如果接口捕获未授权后返回空列表,页面会继续显示管理框架与零计数,用户很难判断是数据被删除还是凭据已过期。这不仅是体验问题,还可能让后续操作在错误会话假设上继续。
已登录但缺少某项权限时应显示禁止访问,不用“找不到记录”代替页面级权限边界。资源级接口有时会为避免枚举而返回不存在,但列表页的功能权限仍应明确表达。客户端根据状态码选择文案,但不自行推断管理角色;服务端在每个数据请求上重新完成会话和资源授权,不把页面中间件当成安全保障。
会话跳转要避免多个并发请求同时触发清理和导航。将未授权处理收敛到一个共享策略,使用一次性标记保证只执行一次退出流程,并丢弃已失效请求的后续错误提示。返回地址只接受站内路径,不从查询参数直接跳转到任意地址。登录成功后重新发起数据获取,不把未授权前的默认空值当成缓存成功结果。
网络错误与服务端错误需要可行动分类
浏览器没有收到响应时,往往没有可信状态码,而服务端故障则应有五开头的响应。两者都可以提供重试,但运维含义不同:网络错误可能只影响当前设备,服务端错误则需要请求标识以便后端排查。错误对象可保存类型、安全文案、是否可重试和服务端返回的脱敏请求标识,但不将原始异常栈或数据库详情直接展示在页面。
自动重试要考虑请求方法和幂等性。列表读取在短暂断网后可以有限次退避,创建、删除和发布等写操作不应因为界面想尽快恢复就盲目重放。即使当前章节主要讨论数据获取,共享的错误层也要保留请求副作用信息。手动重试按钮调用原请求的刷新方法,不通过整页刷新来丢失当前筛选和未保存输入。
持续性故障不应在页面中无限自动重试,这会放大后端压力并使辅助技术不断宣告状态变化。达到上限后保持稳定错误界面,说明数据未能读取,并给出一个可聚焦的重试操作。如果上一份数据仍在展示,要标明它的时间和刷新失败,不把过时内容冒充刚刚成功获取的当前状态。
快速参数变化需要抵御乱序响应
搜索词、筛选或页码快速变化时,旧请求可能比新请求更晚完成。如果每次响应都无条件写入同一个数据引用,页面会显示与当前地址参数不相符的旧结果。为每个请求保存完整键或递增代号,只允许当前键提交数据、错误和状态。如果底层支持取消,在新请求开始时向旧管线传播取消信号,同时仍保留代号校验作最后一道防线。
延迟输入可以减少请求数,但它不会消除乱序,也不适合所有参数。搜索文本可在短暂停顿后请求,用户明确点击页码则应立即反馈。将地址查询作为可恢复状态的真实来源,请求键从规范化查询派生,能在前进后退时命中正确缓存。组件卸载时中断活动请求并丢弃迟到提交,防止在已不存在的页面上修改共享状态。
乱序测试不要依赖真实网络时序。把请求执行器注入可控的延迟承诺,先发起旧参数,再发起新参数,按新后旧、旧后新和其中一个失败的顺序手动完成。断言界面始终只显示当前键对应的数据或错误,加载状态不会因旧请求的完成而提前关闭。这类确定性测试比在浏览器里快速点击更容易稳定重现。
服务端渲染与客户端恢复要共享一次结果
服务端渲染期间完成的数据获取应被序列化到页面负载,客户端水合时使用同一请求键复用,而不是立即再发一次。如果键在两端依赖随机值、本地时区或仅浏览器存在的状态,就会失去去重且可能产生水合差异。请求参数应来自路由、明确的服务端上下文和可序列化值,必须登录的后台页则要确保会话头在服务端请求中被正确传递。
开发环境的客户端导航可能遮住首屏重复请求,所以要在生产构建与真正服务端渲染下观察网络。为接口增加脱敏请求标识,检查同一页面访问是否在服务端与水合后各发一次。若客户端确实需要在水合后验证新鲜度,将这一行为表达为可观测的背景刷新,而不应让它将已有内容切回首次加载骨架。
序列化数据要避免携带服务端秘密、数据库内部字段和过量错误详情。请求在服务端失败时,可以把安全的状态与请求标识序列化给客户端,但不把异常栈和凭据进入页面负载。客户端接管后使用同一错误分支,手动重试成功后才转入空态或内容态。这保证服务端错误不会在水合过程中因默认数据而悄然变成成功空集合。
用组合矩阵证明失败不再伪装成空数据
基础矩阵包含成功有数据、成功空集合、未登录、权限不足、服务端错误和无响应网络中断。对每个案例断言页面标题、可见操作、是否显示旧内容、是否导航和是否出现“暂无数据”。错误案例对空态文案做否定断言,这比只检查某个错误元素存在更能防止两个分支同时渲染。合法空集合则要确认没有重试按钮和错误语义。
刷新矩阵从一份已成功数据开始,分别模拟刷新成功有变化、成功变空、服务端失败和断网。产品可以选择在刷新失败后保留旧内容,但测试必须断言“更新失败”指示和数据时间存在;如果选择阻断,则断言旧列表不再可交互。两种策略都比悄然把旧数据标记为当前成功更诚实,关键是把取舍写进可验证契约。
浏览器端回归要在真实路由上测试服务端渲染、客户端导航、前进后退、快速筛选与会话过期。通过拦截接口精确控制响应顺序,检查旧请求不会覆盖当前页,未授权只导航一次,重试保留当前查询。再检查网络请求数和页面负载,确认首屏没有意外双请求,也没有把内部错误和凭据送进浏览器。
实现片段
const view = computed(() => deriveListState(status.value, data.value, error.value))
评论 · 0