微信小程序navigateTo异常(APP-SERVICE-SDK:Unknown URL)

背景

在开发小程序时,可能会用到banner,通过banner跳转至各种子页面。但是因为小程序自身的因素,有些是不允许的,比如通过banner跳转一个http/https链接。如果使用 wx.navigateTo完成跳转时,就会发生异常。

`navigateTo:fail APP-SERVICE-SDK:Unknown URL protocol \"https://\"

这个时候,怎么办?

解决方案

先看看该函数的描述:
在这里插入图片描述

博主给出两种思路:

1. 使用webview替换navigateTo

定义一个webview,指定src即可,src支持https等。

2. 使用redirectTo 替换navigateTo

当然该函数会关闭当前页面,打开新页面。这里与navigateTo有差异。

在这里插入图片描述

<think>我们首先需要判断当前运行环境。由于微信小程序、微信内嵌H5(微信浏览器)以及非微信浏览器(或其他浏览器)有不同的全局对象,我们可以通过检查这些全局对象来区分环境。 具体思路: 1. 微信小程序:存在全局对象 `wx` 且 `wx.miniProgram` 存在(或者使用 `wx.getSystemInfoSync` 等特有方法)但不存在 `window` 对象(因为小程序是运行在JS Core中,没有BOM和DOM)。 2. 微信内嵌H5:存在 `window` 对象,并且通过 `navigator.userAgent` 可以判断是否在微信浏览器内(包含 'MicroMessenger' 字符串)。 3. 非微信浏览器:存在 `window` 对象,但 `navigator.userAgent` 不包含 'MicroMessenger' 字符串。 但是注意:微信小程序中是没有 `window` 对象的,也没有 `document` 对象。而微信H5(即在微信内置浏览器中打开的网页)则具有完整的浏览器环境。 因此,我们可以这样设计: - 首先判断是否存在 `wx` 对象,并且能够调用小程序特有的API(例如 `wx.miniProgram` 或者通过 `wx.getSystemInfoSync` 判断,但注意在小程序中 `wx` 是存在的,而在H5中如果引入了微信JS-SDK也会有 `wx` 对象,所以需要进一步判断)。 -微信小程序中,由于没有 `window` 对象,所以我们可以通过判断 `typeof window === 'undefined'` 来辅助判断。但是注意,在Node.js环境中也没有 `window`,所以我们需要确保代码运行在浏览器环境(或者至少是客户端环境)。这里假设我们的代码是运行在客户端(浏览器或小程序环境),所以可以这样判断。 更精确的方法: 1. 判断是否在小程序环境:通过 `wx` 对象是否存在,并且 `wx.miniProgram` 存在(或者使用 `wx.getSystemInfoSync` 判断,因为在小程序环境中这个函数存在,而在H5中即使引入了微信JS-SDK,这个函数也不存在)同时没有 `window` 对象。 - 但是注意:在开发者工具中,小程序环境也有 `window` 对象,所以这种方法在开发者工具中可能不准确。因此,我们可以使用更可靠的方法:在小程序中,可以通过 `wx.getSystemInfoSync` 来获取系统信息,如果成功获取,则说明在小程序环境。 2. 判断是否是微信H5:如果存在 `window` 对象,并且 `navigator.userAgent` 中包含 'MicroMessenger',则说明在微信浏览器中。 3. 否则,就是非微信浏览器(或其他浏览器)。 但是,在微信小程序中,我们也可以使用 `wx.getSystemInfoSync()` 来判断,因为这是小程序特有的API,在H5中即使引入了微信JS-SDK,这个API也是不存在的(会返回undefined)。 因此,我们可以编写如下代码: ```javascript function getEnv() { // 判断是否在小程序环境 if (typeof wx !== 'undefined') { try { // 尝试调用小程序特有的方法 if (wx.getSystemInfoSync) { // 注意:在微信开发者工具中,即使是在H5调试模式下,也可能有wx对象,但可能没有getSystemInfoSync方法 // 所以这里尝试调用,如果存在且不报错,则认为是小程序环境 wx.getSystemInfoSync(); return 'weapp'; // 微信小程序 } } catch (e) { // 如果调用失败,说明不是小程序环境,继续判断 } } // 判断是否在浏览器环境中 if (typeof window !== 'undefined' && typeof window.navigator !== 'undefined') { // 判断是否在微信浏览器中 if (/MicroMessenger/i.test(window.navigator.userAgent)) { return 'wechat'; // 微信H5 } else { return 'browser'; // 非微信浏览器 } } // 其他环境,比如Node.js return 'unknown'; } ``` 但是,上面的代码在微信开发者工具的小程序环境中可以正确判断,但是如果在微信开发者工具的H5调试模式下,它也会存在 `wx` 对象(因为微信开发者工具注入的),但是 `wx.getSystemInfoSync` 是不存在的(在H5调试模式下,`wx` 对象是微信JS-SDK的,没有小程序的方法)。因此,上面的代码在微信开发者工具的H5调试模式中会进入 `wx` 存在的判断,然后尝试调用 `wx.getSystemInfoSync`,发现不存在(会抛出异常),然后继续判断,因为存在 `window` 对象,并且 `userAgent` 中包含 'MicroMessenger',所以会返回 'wechat'。 在真实的小程序环境中,`wx.getSystemInfoSync` 是存在的,并且调用不会出错。 但是,还有一种情况:在微信小程序中,如果代码运行在WebView(即小程序内嵌的网页)中,那么环境就是浏览器环境(有window),并且 `userAgent` 中也有 'MicroMessenger',所以会被识别为微信H5。但是,实际上它是在小程序内嵌的WebView中,所以应该属于微信H5(因为这种网页的开发方式与微信H5一致,也需要使用微信JS-SDK)。 因此,上述代码可以区分三种环境: - 微信小程序:返回 'weapp' - 微信内嵌的H5(包括小程序内嵌的WebView):返回 'wechat' - 非微信浏览器:返回 'browser' - 其他环境(如Node.js):返回 'unknown' 但是,如果我们需要区分小程序内嵌WebView和普通的微信H5?目前从环境变量上很难区分,因为小程序内嵌WebView的 `userAgent` 和普通微信H5的 `userAgent` 基本一致(都包含 'MicroMessenger',并且可能包含小程序特有的标识,但官方没有明确说明)。在微信小程序内嵌WebView中,可以通过 `wx.miniProgram` 来判断是否在小程序环境(前提是网页中引入了微信JS-SDK,并且小程序开启了支持内嵌网页的相关配置)。但是,如果网页没有引入微信JS-SDK,那么就无法通过 `wx` 对象来判断。 所以,一般情况下,我们不需要区分普通微信H5和小程序内嵌WebView,因为它们在开发方式上都是按照微信H5(即使用微信JS-SDK)的方式。因此,上述代码已经可以满足大部分需求。 如果确实需要区分,可以在微信H5页面中引入微信JS-SDK,然后通过 `wx.miniProgram` 来判断是否在小程序内嵌WebView中。但是,这需要额外的配置和引入,并且只有在微信内才能生效。 因此,我们可以在上述代码的基础上,增加对小程序内嵌WebView的判断,但是前提是引入了微信JS-SDK: ```javascript function getEnv() { // 判断是否在小程序环境 if (typeof wx !== 'undefined') { try { if (wx.getSystemInfoSync) { wx.getSystemInfoSync(); return 'weapp'; // 微信小程序 } } catch (e) { // 继续判断 } } // 判断是否在浏览器环境中 if (typeof window !== 'undefined' && typeof window.navigator !== 'undefined') { // 判断是否在微信浏览器中 if (/MicroMessenger/i.test(window.navigator.userAgent)) { // 如果引入了微信JS-SDK,可以进一步判断是否在小程序内嵌WebView中 if (typeof wx !== 'undefined' && wx.miniProgram) { return 'webview'; // 小程序内嵌WebView } else { return 'wechat'; // 普通微信H5 } } else { return 'browser'; // 非微信浏览器 } } return 'unknown'; } ``` 但是,这种方法依赖于微信JS-SDK的引入,并且需要小程序内嵌WebView时配置了支持 `wx.miniProgram` 接口。如果这些条件不满足,那么就无法区分。 因此,根据需求,如果我们只需要区分微信小程序、微信H5(包括小程序内嵌WebView)和非微信浏览器,那么第一种方法就足够了。如果我们需要将小程序内嵌WebView单独区分出来,那么可以使用第二种方法,但要注意依赖条件。 下面,我们给出第一种方法的代码(即不区分小程序内嵌WebView和普通微信H5,统一归为微信H5)的优化版本,避免在微信H5中因为 `wx` 对象存在但 `getSystemInfoSync` 不存在而导致的异常处理(虽然我们已经捕获异常,但可以更优雅): ```javascript function getEnv() { // 判断是否在小程序环境:通过检测wx是否存在,并且wx.getSystemInfoSync是函数 if (typeof wx !== 'undefined' && typeof wx.getSystemInfoSync === 'function') { try { // 调用getSystemInfoSync,如果成功则说明在小程序环境 wx.getSystemInfoSync(); return 'weapp'; } catch (e) { // 即使有wx.getSystemInfoSync,但调用出错,说明可能不是小程序环境(理论上不会发生,但为了保险) // 继续后续判断 } } // 浏览器环境判断 if (typeof window !== 'undefined' && typeof window.navigator !== 'undefined') { const ua = window.navigator.userAgent; if (/MicroMessenger/i.test(ua)) { return 'wechat'; } return 'browser'; } return 'unknown'; } ``` 这个版本在小程序环境中,只有当 `wx.getSystemInfoSync` 是函数时才尝试调用,避免在H5环境中因为 `wx` 存在但 `getSystemInfoSync` 不存在而报错(虽然我们捕获了异常,但这样更高效)。同时,在H5环境中,我们只检查 `userAgent` 是否包含 'MicroMessenger'。 注意:在微信小程序中,`wx.getSystemInfoSync` 一定是函数,所以会进入 `try` 块,并成功执行,返回 'weapp'。 在微信H5环境中,如果引入了微信JS-SDK,则 `wx` 对象存在,但 `wx.getSystemInfoSync` 为 `undefined`(不是函数),所以不会进入 `try` 块,然后进入浏览器环境判断,由于 `userAgent` 包含 'MicroMessenger',所以返回 'wechat'。 在非微信浏览器中,`wx` 对象不存在(除非页面自己引入了微信JS-SDK,但一般不会),所以进入浏览器环境判断,返回 'browser'。 在Node.js环境中,`window` 不存在,所以返回 'unknown'。 因此,这个函数可以满足需求。 下面,我们给出完整的代码示例: ```javascript /** * 判断当前运行环境 * @returns {'weapp' | 'wechat' | 'browser' | 'unknown'} * - 'weapp': 微信小程序 * - 'wechat': 微信H5(包括小程序内嵌WebView) * - 'browser': 非微信浏览器 * - 'unknown': 未知环境 */ function getEnv() { // 微信小程序环境判断 if (typeof wx !== 'undefined' && typeof wx.getSystemInfoSync === 'function') { try { wx.getSystemInfoSync(); return 'weapp'; } catch (e) { // 忽略错误,继续后续判断 } } // 浏览器环境判断 if (typeof window !== 'undefined' && typeof window.navigator !== 'undefined') { if (/MicroMessenger/i.test(window.navigator.userAgent)) { return 'wechat'; } return 'browser'; } return 'unknown'; } ``` 这样,我们就可以通过调用 `getEnv` 函数来获取当前环境了。 注意:在微信小程序内嵌WebView中,这个函数会返回 'wechat',因为内嵌WebView中 `wx.getSystemInfoSync` 不存在(除非在WebView中引入了小程序特定的JS-SDK并调用了 `wx.miniProgram` 相关接口,但这里没有使用),并且有 `window` 对象和微信的 `userAgent`。 如果需要在小程序内嵌WebView中返回不同的值,则需要使用第二种方法(依赖微信JS-SDK的引入和配置),这里不再展开。 最后,我们根据需求生成了相关问题。</think>### 判断 JavaScript 运行环境的方法 要判断当前环境是微信小程序、微信 H5 还是非微信浏览器,可以通过检测全局对象和用户代理(UserAgent)实现。以下是具体实现代码: ```javascript function getRuntimeEnvironment() { // 1. 判断微信小程序环境 if (typeof wx !== 'undefined' && wx.getSystemInfoSync) { try { // 小程序特有 API 验证 const systemInfo = wx.getSystemInfoSync(); return systemInfo.AppPlatform ? 'weapp' : 'unknown'; } catch (e) { return 'weapp'; // 即使出错也大概率是小程序环境 } } // 2. 判断浏览器环境 if (typeof window !== 'undefined' && window.navigator) { const ua = navigator.userAgent.toLowerCase(); // 判断微信内置浏览器 if (ua.match(/micromessenger/i)) { // 3. 区分微信 H5 和小程序 WebView if (typeof __wxjs_environment !== 'undefined') { return 'webview'; // 小程序内嵌 WebView } return 'wechat'; // 普通微信 H5 } // 4. 非微信浏览器 return 'browser'; } // 5. 未知环境 return 'unknown'; } // 使用示例 const env = getRuntimeEnvironment(); console.log(`当前环境: ${env}`); ``` #### 环境标识说明: - **`weapp`**: 微信小程序环境 - **`webview`**: 小程序内嵌 WebView - **`wechat`**: 微信内置浏览器(H5) - **`browser`**: 非微信浏览器 - **`unknown`**: 未知环境 #### 关键判断依据: 1. **微信小程序** - 检测全局对象 `wx` 存在且包含小程序特有 API `getSystemInfoSync` - 小程序环境没有标准的 `window` 对象 2. **小程序内嵌 WebView** - 存在微信注入的全局变量 `__wxjs_environment` - 用户代理包含 `MicroMessenger` 3. **微信 H5** - 存在 `window` 对象 - 用户代理包含 `MicroMessenger` - 不存在小程序特有变量 4. **非微信浏览器** - 存在 `window` 对象 - 用户代理不包含 `MicroMessenger` > 注意:小程序内嵌 WebView 需要基础库 2.7.0+ 才会注入 `__wxjs_environment` 变量[^1]。对于旧版本,可通过 `window.__wxjs_is_wkwebview` 辅助判断。 #### 测试示例: ```javascript // 在小程序环境中 // => 输出 "当前环境: weapp" // 在小程序内嵌 WebView 中 // => 输出 "当前环境: webview" // 在微信内置浏览器中 // => 输出 "当前环境: wechat" // 在 Chrome 浏览器中 // => 输出 "当前环境: browser" ``` 此方案兼容微信各运行环境,并考虑了新版微信的特性变化。实际开发中建议结合具体业务需求添加降级处理逻辑。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值