Nuxt中点击浏览器回退取消asyncData请求返回列表页出现404如何解决?
问题根因
这个问题的核心是页面异步逻辑没有取消机制:你点击进入详情页后,asyncData和页面中间件会发起异步请求,在请求未完成时点击回退,页面已经切换回列表页,但之前的异步请求还在后台运行,当请求报错进入catch分支后调用error()方法,会直接将当前展示的列表页替换为404页面,才出现了你遇到的问题。
修复方案
1. 最简适配方案(改动量最小)
在调用error方法前先校验当前路由是否仍为详情页,已经跳转走的情况下直接跳过错误抛出即可:
async asyncData({ $api, route, $auth, error, app }) { try { const { feed } = await $api.Feed.feedDetails( route.params.id, $auth.loggedIn ) if (route.query.origin === 'channel') { const { channel } = await $api.Channels.channelDetails( route.query.cId, $auth.loggedIn ) return { feed, channel_details: channel } } else { return { feed } } } catch (e) { // 新增路由校验:如果已经离开详情页则不抛出404 if (app.router.currentRoute.fullPath !== route.fullPath) return error({ statusCode: 404, message: 'Feed not found' }) } },
2. 彻底优化方案(同时取消无效请求)
结合AbortController在路由切换时直接终止未完成的请求,既可以避免错误触发,还能节省无效请求的带宽消耗:
async asyncData({ $api, route, $auth, error, app }) { // 初始化请求取消控制器 const controller = new AbortController() // 注册路由监听,离开详情页时终止所有未完成请求 const unregisterHook = app.router.beforeEach((to, from, next) => { if (from.name === '你的详情页路由名称') { controller.abort() } next() }) try { // 请求时传入cancel信号,需要你的$api层支持透传axios配置项 const { feed } = await $api.Feed.feedDetails( route.params.id, $auth.loggedIn, { signal: controller.signal } ) if (route.query.origin === 'channel') { const { channel } = await $api.Channels.channelDetails( route.query.cId, $auth.loggedIn, { signal: controller.signal } ) return { feed, channel_details: channel } } else { return { feed } } } catch (e) { // 请求被取消的场景直接返回,不抛出错误 if (e.name === 'AbortError') return if (app.router.currentRoute.fullPath !== route.fullPath) return error({ statusCode: 404, message: 'Feed not found' }) } finally { // 移除路由监听避免内存泄漏 unregisterHook() } },
3. 中间件逻辑优化
你当前的详情页中间件是异步拉取消息、通知列表,同样存在路由切换时的异步错误风险,而且这部分逻辑属于全局通用逻辑,放在详情页会导致重复请求,建议调整到全局布局组件或者登录后的初始化逻辑中执行,不要绑定到详情页的中间件。
内容的提问来源于stack exchange,提问作者Manas Paul
相关产品推荐
相关产品推荐

