Skip to content

Conversation

@shangxueink
Copy link

问题描述

在使用 redirect 插件处理 QQ 跳转链接时,当目标 URL 包含编码的斜杠(%2F)时,会导致跳转到错误的地址。

复现步骤

  1. 访问以下 QQ 跳转链接:

    https://c.pc.qq.com/ios.html?level=14&url=https://anuneko.com/%2F&sublevel=293
    
  2. 插件解析 URL 参数后,%2FURLSearchParams 自动解码为 /

  3. 实际跳转到的地址变成:

    https://anuneko.com//
    

    (注意:域名后有两个斜杠)

  4. 访问该地址时返回错误:

    <Error>
      <Code>AccessDenied</Code>
      <Message>Access Denied</Message>
    </Error>

预期行为

应该跳转到正确的地址:

https://anuneko.com/

(域名后只有一个斜杠)

问题根源

src/utils/querystring.ts 中,parse() 函数使用 URLSearchParams 来解析 URL 参数。URLSearchParams 会自动对参数值进行 URL 解码,将 %2F 解码为 /

当原始 URL 为 https://anuneko.com/%2F 时:

  • %2F 本应表示路径中的单个斜杠 /
  • 解码后变成 https://anuneko.com//(协议后的 // + 解码后的 /
  • 导致路径中出现多余的斜杠

解决方案

src/scripts/redirect/index.ts 中添加了 URL 规范化处理:

  1. 新增 #normalize() 私有方法,用于规范化 URL 路径
  2. 使用正则表达式 /\/+/g 将路径中的多个连续斜杠替换为单个斜杠
  3. #parse() 方法中,在 #ensure() 之后调用 #normalize()

代码变更

async #parse(use: Site['use']) {
  const { query, link, selector, attr } = await use()
  let redirection: Location['href'] | undefined

  if (query) {
    redirection = parse()[query]
  } else if (link) {
    redirection = link
  } else if (selector) {
    redirection = ($(selector) as any)?.[attr ?? 'innerText']
  }

  redirection &&= this.#ensure(redirection.trim())
  redirection &&= this.#normalize(redirection)  // 新增:规范化 URL
  return redirection
}

#normalize(url: string): Location['href'] {
  try {
    const urlObj = new URL(url)
    // 规范化路径,移除多余的斜杠
    // 例如: https://anuneko.com// -> https://anuneko.com/
    urlObj.pathname = urlObj.pathname.replace(/\/+/g, '/')
    return urlObj.href
  } catch (error) {
    warn(error)
    return url
  }
}

测试验证

修复后,访问 https://c.pc.qq.com/ios.html?url=https://anuneko.com/%2F 将正确跳转到 https://anuneko.com/

影响范围

此修复不会影响其他正常的跳转链接,只会规范化路径中的多余斜杠,使 URL 更加标准化。

相关 Issue

此问题可能影响所有通过 URL 参数传递目标地址的跳转场景,特别是当目标 URL 包含编码字符时。

@sakura-flutter
Copy link
Owner

非常感谢~
有个疑问原链接 https://c.pc.qq.com/ios.html?level=14&url=https://anuneko.com/%2F&sublevel=293 https://anuneko.com/%2F 里面的 %2F 是怎么出现的?通常来说原链接中不应该出现两个 //,而且应该都是 %2F%2F 或者都是 // 不会各一半 /%2F

@shangxueink
Copy link
Author

shangxueink commented Dec 1, 2025

非常感谢~ 有个疑问原链接 https://c.pc.qq.com/ios.html?level=14&url=https://anuneko.com/%2F&sublevel=293 https://anuneko.com/%2F 里面的 %2F 是怎么出现的?通常来说原链接中不应该出现两个 //,而且应该都是 %2F%2F 或者都是 // 不会各一半 /%2F

我在windows版本的QQNT里点击了群友发送的链接

https://anuneko.com/

然后经过本脚本处理,跳转到了

https://c.pc.qq.com/ios.html?level=14&url=https://anuneko.com/%2F&sublevel=293
https://anuneko.com//

发现网页内容是

该 XML 文件并未包含任何关联的样式信息。文档树显示如下。
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
</Error>

然后意识到这可能是js脚本所致


不过这个情况似乎比较偶然,现在我再次点击 https://anuneko.com/ 这个链接,

似乎不会跳转到 c.pc.qq.com 了,而是直接打开了链接...


所以我觉得这可能是QQNT对外链的处理问题(?

@sakura-flutter
Copy link
Owner

然后经过本脚本处理,跳转到了
https://c.pc.qq.com/ios.html?level=14&url=https://anuneko.com/%2F&sublevel=293

这一步猜测应该是 QQNT 对外链加了 https://c.pc.qq.com/ios.html 而且对外链额外加了 %2F,感觉应该是 NT 有点问题

不过这个情况似乎比较偶然,现在我再次点击 https://anuneko.com/ 这个链接,
似乎不会跳转到 c.pc.qq.com 了,而是直接打开了链接...

估计它自己又好了,没去加奇怪的东西所以能直接打开了...

后面再观察下看看~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants