vue3+vue-router4:报错Uncaught (in promise) Error: Invalid navigation guard

news2024/10/6 14:34:08
报错图示:

Error: Invalid navigation guard
Uncaught (in promise) Error: Invalid navigation guard
在这里插入图片描述

错误影响描述:

配置开发、测试、生产时候,因为是公众号,所以想在开发环境下免鉴权,不走微信获取openid接口,pinia中定义好openid直接进入项目,遂遇此问题。
因为在async和await中使用,导致next()不能正确执行,查看源码,因为在非生产环境做了此限制,所以只要是生产环境就没问题,但是我就是要dev使用呀。

错误代码示例:
// vant4函数形式的组件
import '@/assets/js/vant4.js'
import '@/assets/css/main.css'
import { getQueryString } from '@/assets/js/common.js'
import { showToast } from 'vant'

import { createApp } from 'vue'
import App from './App.vue'
import router from '@/router/index'
// pinia 共享仓库
import { createPinia ,storeToRefs } from "pinia";
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
// 接口
import { getWechatInfoByCode ,getByOpenid } from '@/api/index'
import { useStore } from '@/store/index'

const pinia = createPinia()
const app = createApp(App)
// 数据持久化
pinia.use(piniaPluginPersistedstate);
// 环境变量挂在全局
app.config.globalProperties.$getEnv = import.meta.env

app.use(pinia)
app.use(router)
app.mount('#app')


// 路由守卫 start
router.beforeEach( async (to, from, next) => {
    const store = useStore();
    // 必须storeToRefs绑定否则拿不到最新值
    const { openid } = storeToRefs(store);
    const { VITE_HOST , VITE_APPID } = import.meta.env
    // 微信公众号appid-开发-基本配置中获取
    const appId = VITE_APPID
    // 获取code后再次跳转路径 window.location.href;例:www.baido.com/#/Home
    const toPath = VITE_HOST + '/#' + to.path
    // 核心步骤,获取code
    const hrefurl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appId + "&redirect_uri=" + encodeURIComponent(toPath) + "&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
    // 从地址栏获取code
    const code = getQueryString('code')
    // 有openid就放行,单纯为了获取openid,无需关心是否登录,绑定等
    const haveOpenidPass = ['/bindAccount' , '/register']
    // 是否账号绑定了openid  
    const isBindAccount = async () => {
        const resGetInfo = await getByOpenid({ openid: openid.value })
        if(resGetInfo.code === 0){
            if(resGetInfo.data){
                // 已绑定
                store.setLoginInfo(resGetInfo.data)
                // dev test 环境都会跳转失效并报错,生产可以正常跳转无报错 !!!
                next()
            }else{
                // 未绑定 
                // 清空store用户信息
                store.setLoginInfo({
                    user:{
                        Uid:''
                    }
                })
                // contactUs 相当于注册,直接通过
                if(to.path == '/contactUs'){
                	// dev test 环境都会跳转失效并报错,生产可以正常跳转无报错 !!!
                    next()
                }else{
                    next({
                        path: '/register'
                    })
                }         
            }
        }else{
            // 请求失败,放行
            showToast(resGetInfo?.info || '请求失败!');
            next()
        }
    }

    /* 路由发生变化修改页面title */
    if (to.meta.title) {
        document.title = to.meta.title;
    }
    /* 判断该路由是否需要登录权限 */
    if (to.matched.some(record => record.meta.requireAuth)) {
        if (openid.value) {
            if(haveOpenidPass.includes(to.path)){
                next()
            }else{
            	// !!!错误的根源在此 !!!
                isBindAccount()
            } 
        } else { //openId不存在
            if (code) { //根据code获取openId
                const res = await getWechatInfoByCode({ code })
                if (res && res.code == 0) {
                    store.setOpenid(res.data.openid)
                    isBindAccount()
                } else {
                    showToast(res?.info || '请求失败!');
                }
            } else {  //获取code
                window.location.replace(hrefurl)
            }
        }
    } else {
        next()
    }
})
// 路由守卫 end

解决方式:

只需要给isBindAccount()函数调用时候加个return就行。

// vant4函数形式的组件
import '@/assets/js/vant4.js'
import '@/assets/css/main.css'
import { getQueryString } from '@/assets/js/common.js'
import { showToast } from 'vant'

import { createApp } from 'vue'
import App from './App.vue'
import router from '@/router/index'
// pinia 共享仓库
import { createPinia ,storeToRefs } from "pinia";
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
// 接口
import { getWechatInfoByCode ,getByOpenid } from '@/api/index'
import { useStore } from '@/store/index'

const pinia = createPinia()
const app = createApp(App)
// 数据持久化
pinia.use(piniaPluginPersistedstate);
// 环境变量挂在全局
app.config.globalProperties.$getEnv = import.meta.env

app.use(pinia)
app.use(router)
app.mount('#app')


// 路由守卫 start
router.beforeEach( async (to, from, next) => {
    const store = useStore();
    // 必须storeToRefs绑定否则拿不到最新值
    const { openid } = storeToRefs(store);
    const { VITE_HOST , VITE_APPID } = import.meta.env
    // 微信公众号appid-开发-基本配置中获取
    const appId = VITE_APPID
    // 获取code后再次跳转路径 window.location.href;例:www.baido.com/#/Home
    const toPath = VITE_HOST + '/#' + to.path
    // 核心步骤,获取code
    const hrefurl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appId + "&redirect_uri=" + encodeURIComponent(toPath) + "&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
    // 从地址栏获取code
    const code = getQueryString('code')
    // 有openid就放行,单纯为了获取openid,无需关心是否登录,绑定等
    const haveOpenidPass = ['/bindAccount' , '/register']
    // 是否账号绑定了openid  
    const isBindAccount = async () => {
        const resGetInfo = await getByOpenid({ openid: openid.value })
        if(resGetInfo.code === 0){
            if(resGetInfo.data){
                // 已绑定
                store.setLoginInfo(resGetInfo.data)
                next()
            }else{
                // 未绑定 
                // 清空store用户信息
                store.setLoginInfo({
                    user:{
                        Uid:''
                    }
                })
                // contactUs 相当于注册,直接通过
                if(to.path == '/contactUs'){
                    next()
                }else{
                    next({
                        path: '/register'
                    })
                }         
            }
        }else{
            // 请求失败,放行
            showToast(resGetInfo?.info || '请求失败!');
            next()
        }
    }

    /* 路由发生变化修改页面title */
    if (to.meta.title) {
        document.title = to.meta.title;
    }
    /* 判断该路由是否需要登录权限 */
    if (to.matched.some(record => record.meta.requireAuth)) {
        if (openid.value) {
            if(haveOpenidPass.includes(to.path)){
                next()
            }else{
                // 处理非prod环境下,控制台异常,报错无法跳转问题
                return isBindAccount()
            } 
        } else { //openId不存在
            if (code) { //根据code获取openId
                const res = await getWechatInfoByCode({ code })
                if (res && res.code == 0) {
                    store.setOpenid(res.data.openid)
                    isBindAccount()
                } else {
                    showToast(res?.info || '请求失败!');
                }
            } else {  //获取code
                window.location.replace(hrefurl)
            }
        }
    } else {
        next()
    }
})
// 路由守卫 end

备注:

vue3的ref变量使用必须加.value,卧槽,反人类啊,开倒车!!!经常忘记,导致我疯狂debug

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/777321.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PHP要怎么学--【思维导图知识范围】

强撸项目 总目录在此 专辑工作量PHP登陆/php登录–【强撸项目】难度★✫✰✰✰PHP注册/登录/发邮件–【强撸项目】★★★✫✰PHP在线相册–【强撸项目】★★★★✫–【强撸项目】––【强撸项目】––––– 文章目录 本系列校训学习资源的选择环境的问题本人推荐 PHP视频的知…

C语言-分支语句和循环

目录 【1】字符输入输出 【2】C语言下的垃圾字符回收 【3】分支语句 【4】循环 练习: 【1】字符输入输出 按字符的输入输出 int getchar(void); 功能:从终端输入一个字符 参数:无 返回值:输入字符的ASCII值int putchar(int…

pandas常用方法

一、提要 pandas对于处理表格类数据来说是非常方便的模块,同时也是做数据分析绕不开的第三方库。这里将工作中常用到的各种处理方法记录下来二、常用方法 接下来的以 df 表示我们要处理的 dataframe 表格数据 1、取值 # 循环遍历取值 for i in range(len(df)):y…

Spring Cloud之Gateway网关应⽤

使⽤⽹关对静态化微服务进⾏代理(添加在它的上游,相当于隐藏了具体微服务的信息,对外暴露的是⽹关)。 1. 右键⽗⼯程【 yx-parent 】选择【 New 】 - 【 Module 】选项,然后选择创建【 Maven 】类型项⽬(不…

以高质量产业载体为底色,绘就珠海高新区产业发展新图景

【作者】珠海高新招商 “珠海高新招商”以招商运营为核心,聚焦珠海工业园区、珠海5.0产业园等招商引资工作,依托专业的招商团队和丰富的创新资源,为企业提供产业园入驻、平台搭建、产业政策咨询、科技服务等全流程专业服务。推动高新区招商引…

17 数组动态初始化

动态初始化:初始化时只指定数组长度,由系统为数组分配初始值。 格式:数据类型[] 数组名 new 数据类型[数组长度] package demo;public class Demo11 {public static void main(String[] args) {// 动态初始化数组:数据类型[] 数…

日撸java三百行day77-80

文章目录 说明GUI1. GUI 总体布局2. GUI 代码理解2.1 对话框相关控件2.1.1 ApplicationShowdown.java(关闭应用程序)2.1.2 DialogCloser.java(关闭对话框)2.1.3 ErrorDialog.java(显示错误信息)2.1.4 HelpD…

深度学习模型量化、剪枝、压缩

fp16是指采用2字节(16位)进行编码存储的一种数据类型; fp32是指采用4字节(32位); fp16和fp32相比对训练的优化: 1.内存占用减少:应用fp16内存占用比原来更小,可以设置更大的batch_size 2.加速计算:加速…

CentOS5678 repo源 阿里云/腾讯云开源镜像站 repo 地址

CentOS5678 repo 地址 阿里云开源镜像站 https://mirrors.aliyun.com/repo/ CentOS5678 repo 地址 腾讯云开源镜像站 http://mirrors.cloud.tencent.com/repo/ CentOS-5.repo https://mirrors.aliyun.com/repo/Centos-5.repo [base] nameCentOS-$releasever - Base - mirror…

DuDuTalk :做4G智能工牌领域标杆品牌,用语音智能构建完美沟通

数字经济高速发展,AI 成为数字经济时代的核心生产力,驱动数字经济纵深发展,在此情境下,作为AI基石的语音数据价值也在不断释放。企业纷纷加强对客服、营销等服务和销售资源部门的投入,试图从语音数据入手,利…

如何使用windows搭建WebDAV服务,并内网穿透公网访问【无公网IP】

文章目录 windows搭建WebDAV服务,并内网穿透公网访问【无公网IP】1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透,将WebDav服务暴露在公网3.1 打开Web-UI管理界面3.2 创建隧道3.3 查看在线隧道列表3.4 浏览器访问测试 4. 安装Raidrive客户…

NodeJS实现支付宝沙箱支付 ②③

文章目录 前言版权声明Alipay SDK 沙箱环境简介Node环境要求沙箱环境配置下载所需模块准备前端静态页面以及Node服务器文件夹规范AlipaySdk 配置准备AlipaySdk 代码演示 Alipay实例化 ~ alipay.sdk 文件 AlipayForm ~ alipayForm文件 AlipayFormStatus ~ alipayForm文件 …

deeplabv3+源码之慢慢解析 第四章network文件夹(1)backbone文件夹(a1)hrnetv2.py--4个函数和可执行代码

系列文章目录(更新中) 第一章deeplabv3源码之慢慢解析 根目录(1)main.py–get_argparser函数 第一章deeplabv3源码之慢慢解析 根目录(2)main.py–get_dataset函数 第一章deeplabv3源码之慢慢解析 根目录(3)main.py–validate函数 第一章deeplabv3源码之慢…

使用NRF52840 USB Dongle进行Wireshark蓝牙抓包

一、搭建软硬件环境 1.1、准备NRF52840 USB Dongle一个: 1.2、下载Wireshark软件 https://2.na.dl.wireshark.org/win64/Wireshark-win64-4.0.7.exe 1.3、下载Nodic官方解析工具包 nRF Sniffer for Bluetooth LE - Downloads - nordicsemi.com 1.4、下载Python P…

中文数据下载

研究AI离不开数据,数据库可以说是AI的半壁天下。有链接的数据库下载是很nice的。 语音数据集整理 目录 1.Mozilla Common Voice. 2 2.翻译和口语音频的大型数据库Tatoeba. 2 3.VOiCES Dataset 3 4. LibriSpeech. 4 5.2000 HUB5 English:... 4 6.…

Java文件流和网络流的原理以及流解析过程

流我们可以理解为水流,流的传输就相当于在水管里传输,本篇博客主要介绍流的原理和解析过程,学疏才浅,抛砖引玉,大佬勿喷。 文件流 假设我们收到了一个以Unicode编码的文件流,对于该文件流所表示的内容我们…

Java显示日期和时间中间的CST表示什么意思

例如,用Java代码System.out.println(new Date())语句打印出了当前的日期和时间信息,结果显示:Tue Jul 18 18:42:57 CST 2023 package com.thb;import java.util.Date; import java.util.Locale; import java.util.TimeZone;public class Tes…

Office史上最大升级!GPT-4接入Office全家桶!Excel到PPT动嘴就能做!

3月17日,微软宣布将GPT-4融入了Office全家桶。 这意味着,不管是Word、PPT、Excel,还是Outlook、Teams、Microsoft Viva、Power Platform,所有这些办公软件,通通都会得到GPT-4的加持! 直接改名吧&#xff0…

this指针/闭包及作用域(进阶)

一.作用域链 1.通过一个例子 let aglobalconsole.log(a);//globalfunction course(){let bjsconsole.log(b);//jssession()function session(){let cthisconsole.log(c);//Windowteacher()//函数提升function teacher(){let dstevenconsole.log(d);//stevenconsole.log(test1,…

Ae 效果:CC Kaleida

风格化/CC Kaleida Stylize/CC Kaleida 万花筒是一种装置或玩具,通过多次反射和镜像,将图像分割成多个对称和重复的图案。CC Kaleida(CC 万花筒) 效果通过类似的方式在图像上创建镜像和对称的视觉效果。 提示: 由于 CC…