This commit is contained in:
zhangjianjun 2026-08-31 10:49:53 +08:00
parent fa5d736cae
commit d3232ab4ee
2 changed files with 91 additions and 7 deletions

View File

@ -46,6 +46,51 @@ describe('parseLaunchQuery', () => {
expect(parseLaunchQuery({ scene: '/p/PREV9' }).prevId).toBe('PREV9') expect(parseLaunchQuery({ scene: '/p/PREV9' }).prevId).toBe('PREV9')
}) })
it('unpacks jump params stuffed into scene when & is encoded as %26', () => {
expect(
parseLaunchQuery({
scene:
'%2Fh%2FKZ9Q%26token=67738e89-4f74-4d9b-bdcc-1d30dc11f0fd%26host=nb.batiao8.com%26package=10044%26phone=17316703138',
})
).toEqual({
token: '67738e89-4f74-4d9b-bdcc-1d30dc11f0fd',
host: 'nb.batiao8.com',
packageId: '10044',
scene: '/h/KZ9Q',
linkId: 'KZ9Q',
shareId: '',
prevId: '',
phone: '17316703138',
})
})
it('unpacks jump params after WeChat decodes %26 into &', () => {
expect(
parseLaunchQuery({
scene:
'/h/KZ9Q&token=67738e89-4f74-4d9b-bdcc-1d30dc11f0fd&host=nb.batiao8.com&package=10044&phone=17316703138',
})
).toEqual({
token: '67738e89-4f74-4d9b-bdcc-1d30dc11f0fd',
host: 'nb.batiao8.com',
packageId: '10044',
scene: '/h/KZ9Q',
linkId: 'KZ9Q',
shareId: '',
prevId: '',
phone: '17316703138',
})
})
it('keeps explicit query fields over values stuffed into scene', () => {
expect(
parseLaunchQuery({
scene: '/h/KZ9Q&token=from-scene&phone=13800138000',
token: 'from-query',
}).token
).toBe('from-query')
})
it('ignores empty values', () => { it('ignores empty values', () => {
expect(parseLaunchQuery({})).toEqual({ expect(parseLaunchQuery({})).toEqual({
token: '', token: '',
@ -99,5 +144,23 @@ describe('resolveLaunchQuery', () => {
phone: '', phone: '',
}) })
}) })
it('uses stuffed scene params instead of scheme defaults', () => {
expect(
resolveLaunchQuery({
scene:
'/h/KZ9Q&token=h5-token&host=h5test.batiao8.com&package=20001&phone=17316703138',
})
).toEqual({
token: 'h5-token',
host: 'h5test.batiao8.com',
packageId: '20001',
scene: '/h/KZ9Q',
linkId: 'KZ9Q',
shareId: '',
prevId: '',
phone: '17316703138',
})
})
}) })

View File

@ -41,7 +41,7 @@ function safeDecode (value: string) {
function parseSceneIds (scene: string) { function parseSceneIds (scene: string) {
const decoded = safeDecode(scene).trim() const decoded = safeDecode(scene).trim()
const matched = decoded.match(/\/(h|s|p)\/([^/?#]+)/) const matched = decoded.match(/\/(h|s|p)\/([^/?#&]+)/)
if (!matched) { if (!matched) {
return { linkId: '', shareId: '', prevId: '' } return { linkId: '', shareId: '', prevId: '' }
} }
@ -52,14 +52,35 @@ function parseSceneIds (scene: string) {
return { linkId: '', shareId: '', prevId: id } return { linkId: '', shareId: '', prevId: id }
} }
export function parseLaunchQuery (raw: Record<string, string | undefined> = {}): LaunchQuery { function expandLaunchRaw (raw: Record<string, string | undefined> = {}) {
const scene = safeDecode(asText(raw.scene)) const scene = asText(raw.scene)
if (!scene) return raw
const decoded = safeDecode(scene).replace(/%26/gi, '&')
const amp = decoded.indexOf('&')
if (amp < 0) return raw
const extra: Record<string, string> = {}
new URLSearchParams(decoded.slice(amp + 1)).forEach((value, key) => {
extra[key] = value
})
return { return {
token: asText(raw.token), ...extra,
host: asText(raw.host), ...raw,
packageId: asText(raw.package), scene: decoded.slice(0, amp),
}
}
export function parseLaunchQuery (raw: Record<string, string | undefined> = {}): LaunchQuery {
const expanded = expandLaunchRaw(raw)
const scene = safeDecode(asText(expanded.scene))
return {
token: asText(expanded.token),
host: asText(expanded.host),
packageId: asText(expanded.package),
scene, scene,
phone: asText(raw.phone), phone: asText(expanded.phone),
...parseSceneIds(scene), ...parseSceneIds(scene),
} }
} }