遇到的问题

在使用 Dream2.0 Plus 主题时,友链页面里,有几个博主的头像怎么都刷不出来,F12 一看全是 400 Bad Request

奇怪的是,把头像链接复制到浏览器地址栏直接打开,图片又是正常的。而且不是所有头像都坏,只有部分挂了。

后台检查了一圈,发现规律:头像 URL 带中文路径的才会炸

Dream2.0 Plus 友链头像 400 错误:双重编码陷阱排查

排查原因

查看代码后终于发现了根本原因所在:双重编码问题(核心问题)

控制台报错如下:

GET https://www.example.ccom/upload/%25E5%25A4%25B4%25E5%2583%258F.png  400 (Bad Request)

注意 URL 里的 %25——这是 % 被再次编码的结果。

原代码中:

function setSafeSrc(element, url) {
  var isSafe = /^(https?|data:image\/[a-z]+;base64|\/)/i.test(url)
  element.src = isSafe ? encodeURI(url) : ''  

当 URL 已经是编码状态(如 %E5%A4%B4%E5%83%8F.png ), encodeURI() 会再次编码,变成了 %25E5%25A4%25B4%25E5%2583%258F.png

编码过程变成了这样:

原始中文:     头像.png
一次编码后:   %E5%A4%B4%E5%83%8F.png         ← 正确的
二次编码后:   %25E5%25A4%25B4%25E5%2583%258F.png  ← % 被编码成 %25,炸了

解决方案

修改位置

文件 : templates/links.html

行号 :第 8-12 行( setSafeSrc 函数)

function setSafeSrc(element, url) {
            // 允许:http/https/data:image 协议 或 相对路径(以/开头)
            var isSafe = /^(https?|data:image\/[a-z]+;base64|\/)/i.test(url)
            element.src = isSafe ? encodeURI(url) : '' // 不安全则清空
          }

修改为:

function setSafeSrc(element, url) {
  // 空值检查:防止 url 为空或 undefined 时报错
  if (!url) { element.src = ''; return; }
  
  // 安全协议检查:只允许 http/https/data:image/相对路径
  var isSafe = /^(https?|data:image\/[a-z]+;base64|\/)/i.test(url);
  if (!isSafe) { element.src = ''; return; }
  
  // 编码检测:检查URL是否已包含 %XX 格式的编码字符
  // 如果已编码则直接使用,避免双重编码导致 400 Bad Request
  // 如果未编码则使用 encodeURI() 处理中文等特殊字符
  element.src = /%[0-9A-Fa-f]{2}/.test(url) ? url : encodeURI(url);
}

修改说明

修改内容 如下:

  1. 增加空值检查

  2. 增加已编码 URL 检测

  3. 条件执行 encodeURI()
    修复效果 :解决了中文头像 URL 无法显示的问题,同时兼容已编码 URL 的情况。

验证修改

  1. 修改保存后,进入后台 Dream2.0 Plus 主题设置

  2. 执行清理模板缓存

  3. 刷新前台友链页面,中文头像正常显示


这个坑的本质是前端编码逻辑没有考虑输入状态。如果 URL 来自用户输入或数据库,可能已经是编码态,也可能是原始态,直接 encodeURI 会埋雷。

判断逻辑很简单: %XX就不编码,没有才编码。搞定!