diff --git a/common/js/util.js b/common/js/util.js index 2c55fe2..76b456f 100644 --- a/common/js/util.js +++ b/common/js/util.js @@ -282,7 +282,14 @@ export const resolvePageUrl = (page_key, params = {}) => { Object.keys(params).forEach(function (key) { const value = params[key]; if (value === null || value === undefined || value === '') return; + // H5:浏览器不自动编码,需要手动 encodeURIComponent + // 小程序/App:uni.navigateTo 会自动编码,这里不能再 encode,否则双重编码 + // #ifdef H5 parts.push(key + '=' + encodeURIComponent(value)); + // #endif + // #ifndef H5 + parts.push(key + '=' + value); + // #endif }); if (parts.length > 0) { url = url + (url.indexOf('?') !== -1 ? '&' : '?') + parts.join('&'); @@ -643,18 +650,25 @@ export default { // 2. 合并 param:同 key 时新值覆盖旧值,杜绝 ?name=A&name=B 这种重复 const merged = Object.assign({}, existingParams, param || {}); - // 3. 统一编码。decode -> encode 双向 roundtrip 兼具两种语义: - // - 调用方传原始值(/pages_tool/index/diy?name=XXX) -> encode 后 %2F%3F... - // - 调用方已传编码值(%2F%3F...) -> decode 还原 -> encode 还原回去,不会被二次编码 - // - 任何不能 decode 的非法序列(如裸 %) 走 catch 路径,直接 encode + // 3. 参数编码策略,按平台区分: + // - 小程序/App: uni.navigateTo / router.pushUrl 内部会自动对 url 做一次编码, + // 若在 JS 侧再 encodeURIComponent 一次,会被平台再编码一层,目标页 onLoad(options) + // 只 decode 一次后仍是编码形态(如 %25E6%25B2%2599%25E5%258F%2591 -> %E6%B2%99%E5%8F%91) + // => 这里必须保持原始值,完全交给平台去编码 + // - H5: 浏览器不会自动编码 url,若参数含 & ? = 等特殊字符会被 queryString 错位解析 + // => 这里仍需手动 encodeURIComponent,decode->encode roundtrip 兼容调用方已编码的入参 const safeEncode = (v) => { const s = v == null ? '' : String(v); - // try { - // return encodeURIComponent(decodeURIComponent(s)); - // } catch (e) { - // return encodeURIComponent(s); - // } + // #ifdef H5 + try { + return encodeURIComponent(decodeURIComponent(s)); + } catch (e) { + return encodeURIComponent(s); + } + // #endif + // #ifndef H5 return s; + // #endif }; const queryStr = Object.keys(merged) .map(k => safeEncode(k) + '=' + safeEncode(merged[k])) @@ -2020,10 +2034,12 @@ export default { // 判断当前 URL 是否已经包含查询参数,决定使用 ? 还是 & const separator = targetUrl.includes('?') ? '&' : '?'; - // 遍历参数对象,手动进行 encodeURIComponent 编码并拼接 + // 遍历参数对象,拼接参数 + // 小程序/App 端:uni.navigateTo/router.pushUrl 内部会自动对 url 编码, + // 这里不能再 encodeURIComponent,否则会被平台再编码一层导致双重编码 const queryString = Object.entries(params) .filter(([_, value]) => value !== undefined && value !== null) - .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`) + .map(([key, value]) => `${key}=${value}`) .join('&'); // 重新拼接成完整的 URL diff --git a/pages_tool/help/list.vue b/pages_tool/help/list.vue index af57324..1974570 100644 --- a/pages_tool/help/list.vue +++ b/pages_tool/help/list.vue @@ -50,9 +50,18 @@ export default { helpDetail(e) { // #ifndef MP-WEIXIN if (e.link_address) { + // H5:浏览器不自动编码,需要手动 encodeURIComponent + // 其他小程序平台(HarmonyOS 等):uni.redirectTo 内部会自动编码,不能再 encode,否则双重编码 + // #ifdef H5 uni.redirectTo({ url: '/pages_tool/webview/webview?src=' + encodeURIComponent(e.link_address) }); + // #endif + // #ifndef H5 + uni.redirectTo({ + url: '/pages_tool/webview/webview?src=' + e.link_address + }); + // #endif } else { this.$util.redirectTo('/pages_tool/help/detail', { id: e.id