一、背景
在 uni-app 开发支付宝内嵌 H5 业务时,由于页面获取参数不规范导致页面跳转异常、参数丢失或解析报错,测试表现为白屏
javascript
//❌错误写法
let tmp = decodeURIComponent(location.href)
let dataObj = JSON.parse(tmp.split('=')[1])
这种取法非常基础,没有考虑到多个参数的情况
二、核心问题:URL 被篡改的真相
1. 现象:页面展示 URL 与原始真实访问地址不一致
在支付宝内跳转至第三方 H5 时,浏览器地址栏展示的 URL 并非代码中写入的原始链接,而是经过了网关处理后的"新链接"。
具体差异示例:
-
原始链接结构:
htmlhttps://xxx.com/h5/?timestamp=原始时间戳#/subpkg/page?json=加密业务参数 -
实际展示链接结构:
htmlhttps://xxx.com/h5/?timestamp=最新时间戳&flowT=流水号&flowSig=链路签名#/subpkg/page?json=加密业务参数
直观差异:
?后的查询参数被完全重写(时间戳更新,追加了支付宝内部风控参数)。#后的路由路径及业务参数(json)完整保留,未发生任何变化。
2. 原理:网关的"隐形重定向"
这是支付宝内核级的安全策略。网关在后台执行 302 重定向,重写 HTTP 请求参数(? 后)以进行风控验签,而前端路由片段(# 后)不参与 HTTP 请求,因此绝对安全。
3. 误区纠正:白名单的作用
- 能解决:消除"即将离开支付宝"的拦截弹窗,解除域名访问限制。
- 不能解决 :无法阻止 网关对
?后参数的篡改。无论域名是否备案,Query 参数始终不可靠。
三、开发规范:参数存放与获取
1. 铁则:业务参数必须放 Hash
所有核心业务参数,严禁放在
?后,必须放在#后。
- 原因 :
#后的参数在网关重定向过程中全程"只读",是唯一稳定的数据传输通道。
2. 取参规范:严禁二次解码
场景一:页面内部 (onLoad)
uni-app 框架已自动对 onLoad 的参数进行了一次 decodeURIComponent 解码。
- 正确做法:直接使用。
- 错误风险 :手动再次解码会导致数据中的
%符号解析异常(报错URIError或数据损坏)。
javascript
// ✅ 正确
onLoad(options) {
if (options.json) {
const data = JSON.parse(options.json)
}
}
// ❌ 错误:禁止二次解码
// const data = JSON.parse(decodeURIComponent(options.json))
场景二:全局入口 (App.vue)
App.vue 没有 onLoad,需使用原生 API 手动解析,且必须手动进行一次解码。
javascript
onLaunch() {
const hash = window.location.hash
const paramStr = hash.split('?')[1] || ''
const params = this.parseUrlParam(paramStr)
if (params.json) {
// 原生场景需手动解码
const bizData = JSON.parse(decodeURIComponent(params.json))
}
},
methods: {
parseUrlParam(str) {
const obj = {}
if (!str) return obj
str.split('&').forEach(item => {
const [key, val] = item.split('=')
obj[key] = val ? decodeURIComponent(val) : ''
})
return obj
}
}