z***@foxmail.com
z***@foxmail.com
  • 发布:2026-02-27 15:09
  • 更新:2026-02-28 16:03
  • 阅读:169

【报Bug】H5 navigateTo打开页面后,当前 location.href 编码异常

分类:uni-app

产品分类: uniapp/H5

PC开发环境操作系统: Mac

PC开发环境操作系统版本号: 26.3

浏览器平台: Chrome

浏览器版本: 145.0.7632.111(正式版本) (arm64)

项目创建方式: CLI

CLI版本号: 3.0.0-alpha-4070620250731001

示例代码:
<template>  
  <div>  
    <button @click="navigateTo('/pages/components/swiper/index?name=usmile%e7%94%b5')">  
      swiper1  
    </button>  
    <button @click="navigateTo('/pages/components/swiper/index?name=usmile电')">  
      swiper2  
    </button>  

    {{ option }}  
  </div>  
</template>  

<script setup lang="ts">  
import { onLoad } from '@dcloudio/uni-app';  
import { ref } from 'vue';  

const option = ref("")  
onLoad((op) => {  
  console.log('onLoad', op)  
  option.value = JSON.stringify(op || {})  
})  

function navigateTo(url: string) {  
  uni.navigateTo({  
    url: url,  
  })  
}  
</script>  

<style scoped></style>  

操作步骤:

见BUG描述和附件demo工程

uni.navigateTo({url: '/pages/components/swiper/index?name=usmile%e7%94%b5'})

预期结果:

跳转后

location.herf =  http://localhost:5173/#/pages/components/swiper/index?name=usmile%e7%94%b5

实际结果:

跳转后

location.herf =  http://localhost:5173/#/pages/components/swiper/index?name=usmile%25e7%2594%25b5

bug描述:

本地调试,http://localhost:5173/

通过uni.navigateTo({url: '/pages/components/swiper/index?name=usmile%e7%94%b5'}) 打开页面后。
通过location.href获取到的页面地址为 http://localhost:5173/#/pages/components/swiper/index?name=usmile%25e7%2594%25b5
看得出来location.href拿到的name = encodeURIComponent('usmile%e7%94%b5')

附件是demo

2026-02-27 15:09 负责人:DCloud_UNI_OttoJi 分享
已邀请:
Ask小助手

Ask小助手

欢迎到专业群( uni-app 官方技术交流群 1 ) 咨询,群中有相关专业的管理员和群友。

作为官方评审人员,我来对这个 bug 反馈进行评审:

一、反馈完整性评估

✅ 内容完整性较好

  • BUG标题:明确指出了"H5 navigateTo打开页面后,当前 location.href 编码异常"
  • BUG描述:详细说明了问题现象,包括具体的URL变化对比
  • 代码示例:提供了可直接运行的最小复现demo
  • 复现步骤:与代码示例结合,描述清晰
  • 预期/实际结果:对比明确,用具体URL展示差异
  • 环境信息:包含了平台(Mac)、工具版本(HBuilderX正式版)等关键信息

⚠️ 需要补充的信息

  1. HBuilderX具体版本号:只写了"正式版",建议补充如"4.87"这样的具体版本
  2. uni-app版本:未明确是vue2还是vue3项目
  3. 测试浏览器:未说明测试用的浏览器及版本

二、问题合理性分析

✅ 预期结果合理

用户期望的location.href保持usmile%e7%94%b5是合理的,因为:

  • %e7%94%b5已经是URL编码后的"电"字
  • 不应该被二次编码为%25e7%2594%25b5

✅ 实际结果确认异常

实际出现的二次编码现象确实不符合标准URL处理规范,属于异常行为。

三、技术依据分析

根据知识库中的router文档

  • 明确提到"参数中出现空格等特殊字符时需要对参数进行编码"
  • 但文档中使用的是encodeURIComponent单次编码,没有提及二次编码问题

四、结论与建议

? 确认为有效bug

这是一个有效的bug反馈,问题表现为:

  • uni-app H5端路由处理时对已URL编码的参数进行了二次编码
  • 影响了通过location.href获取URL的准确性

? 处理建议

  1. 优先级:建议标记为中优先级,影响H5端URL参数解析
  2. 临时方案:用户可在目标页面使用decodeURIComponent二次解码作为临时解决方案
  3. 修复方向:需要检查uni-app H5端路由跳转时对URL参数的处理逻辑,避免对已编码参数重复编码

? 补充验证建议

建议用户在目标页面添加验证代码:

onLoad((options) => {  
  console.log('原始参数:', options.name)  
  console.log('解码后:', decodeURIComponent(options.name))  
  console.log('二次解码:', decodeURIComponent(decodeURIComponent(options.name)))  
})

这个反馈整体质量较高,信息完整,复现路径清晰,可以进入bug修复流程。

内容为 AI 生成,仅供参考
z***@foxmail.com

z***@foxmail.com (作者) - ?网络姻缘一线牵 珍惜这段缘?

@CODE_XU 大佬帮看看

z***@foxmail.com

z***@foxmail.com (作者) - ?网络姻缘一线牵 珍惜这段缘?

@DCloud_UNI_FengXY 大佬帮看看

骑猪o0o找牛

骑猪o0o找牛 - 一挖一麻袋

先说 原理吧

  1. uni.navigateTo后

  2. 然后会调用beforeInvokeApi
    /node_modules/@dcloudio/uni-h5/dist/uni-h5.es.js

  3. 然后调用normalizeUrl

  4. 然后调用encodeQueryString
    也就是 这里 解析 你 传递的 url, 然后 又给你 编码了一次

    // 要编码...  
    function encodeQueryString(url) {  
    if (!isString(url)) {  
      return url;  
    }  
    const index2 = url.indexOf("?");  
    if (index2 === -1) {  
      return url;  
    }  
    // 获取query  
    const query = url.slice(index2 + 1).trim().replace(/^(\?|#|&)/, "");  
    if (!query) {  
      return url;  
    }  
    // 页面路由  
    url = url.slice(0, index2);  
    // 遍历获取 query  
    const params = [];  
    query.split("&").forEach((param) => {  
      const parts = param.replace(/\+/g, " ").split("=");  
      const key = parts.shift();  
      const val = parts.length > 0 ? parts.join("=") : "";  
      // 然后 编码了一次....  
      params.push(key + "=" + encodeURIComponent(val));  
    });  
    return params.length ? url + "?" + params.join("&") : url;  
    }  
  5. 准备调用 vue-router

    function navigate({ type, url, tabBarText, events, isAutomatedTesting }, __id__) {  
    if (process.env.NODE_ENV !== "production" && !__UNI_FEATURE_PAGES__) {  
    
    const router = getApp().$router;  
    // 这里的 url  已经是对  url上的query  编码一次的了  
    // parseUrl  解码 一次, 然后 丢给  vue-router  
    
    // 那么到vue-router , 拿到的 就是 实际 uni.navigateTo 最初传递的 ~~~  
    const { path, query } = parseUrl(url);  
    return new Promise((resolve, reject) => {  
      const state2 = createPageState(type, __id__);  
      router[type === "navigateTo" ? "push" : "replace"]({  
        path,  
        query,  // 这里的  query 就是  你最初 uni.navigateTo 传递的 url上的 query  
        state: state2,  
        force: true  
      }).then((failure) => {  
        ...  
        ...  
      });  
    });  
    }
  6. vue-router要 push 跳转了,

    源码里面 会 使用 fullPath 作为 history.pushState 的参数

    而这个 fullPath 是 经过 vue-router 的 url编码 , 不等同于 encodeURIComponent,

    vue-router的编码是

    vue-router 有个 配置项 就是 配置 这个, 叫stringifyQuery

    function encodeQueryValue(text) {  
    return (commonEncode(text)  
      // Encode the space as +, encode the + to differentiate it from the space  
      // /\+/g  
      .replace(PLUS_RE, '%2B') //   
      // /%20/g  
      .replace(ENC_SPACE_RE, '+')  
      // /#/g  
      .replace(HASH_RE, '%23')  
      // /&/g  
      .replace(AMPERSAND_RE, '%26')  
      // /%60/g  
      .replace(ENC_BACKTICK_RE, '`')  
      // /%7B/g  
      .replace(ENC_CURLY_OPEN_RE, '{')  
      // /%7D/g  
      .replace(ENC_CURLY_CLOSE_RE, '}')  
      // /%5E/g  
      .replace(ENC_CARET_RE, '^'));  
    }   

完整流程
如果 你 先编码 再调用 uni.navigateTo

那就是
编码1次 -> uni.navigateTo -> uni又编码(此时 编码2次) -> 丢给 vue-router, 解码1 (此时 编码又变成1) -> vue-router 生成fullPath 给 history.pushState(编码又变成2次)

最终链接上 显示 的 编码2次的

  • 骑猪o0o找牛

    再说一下 h5端 onLoad 中 参数 options 的 问题


    options 是啥呢?


    源码


     setup(instance2) {  
    instance2.$pageInstance = instance2;
    // 这里 就是 取的 useRoute
    const route = usePageRoute();

    // 先获取 query , 这里的query 就是 vue-router 时 拿到的 原文query , 跳转的时候 用的是 route.fullPath 是 路由 + 编码后的 query
    // uni 这里 又 解码了一次...
    const query = decodedQuery(route.query);

    // 保存一下, 调用 onLoad 使用的就是 __pageQuery
    instance2.attrs.__pageQuery = query;

    getPage$BasePage(instance2.proxy).options = query;
    instance2.proxy.options = query;

    ...
    ...

    }

    也就是 从 useRoute 获取 当前路由 对象,


    useRoute().query 就是 你最初 uni.navigateTo传递的 url上的 query



    • 你如果 编码 , 那这里就是编码的

    • 如果 没有编码, 那么 这里就是 没有编码的


    假设 你传递的是 /page/cc/dxd?gg=%E5%9C%9F%E8%B1%86


    那么 useRoute().query 就是 { "gg": %E5%9C%9F%E8%B1%86 }


    然后 被uni 解码了 ,

    在 onLoad 中的 参数 就是 { "gg": "土豆" }

    2026-02-28 13:17

[已删除]

[已删除]

信息没有损失,都可以通过 decode 得到 name 原始值。如果你希望保证不同参数跳转结果完整,可以自行处理 encode/decode

要回复问题请先登录注册