如何在知乎使用动态头像

如何在知乎使用动态头像

大家如果在web端或者app端的点赞列表中看到我的头像的话,将会看到的是一个动图的效果。具体效果如下:

web端实现效果:

app端效果

根据app端的版本不同,生效的部分也不相同。就本人的版本(10.91.0)而言,仅在点赞列表中生效。app端用户可以点击本文的点赞列表查看其他复现成功人员的效果。也可以参照此效果:

实现方式

原理分析

知乎可以实现动态头像的核心原因在于知乎头像的显示时是直接从图床中加载头像文件,实际上并不会根据文件名进行类型检查。换句话说,虽然在上传时会强行指定为png/jpg格式,但是我们只需要保证上传内容是一个具有自明性的动图,那么知乎的web端实际上就能直接根据图片的内容正确地解析并显示出来。

考虑到知乎对于GIF的支持方式实际上也是借助webp格式,所以只需要我们在上传头像时能够上传一个文件内容为『完整的webp格式』的文件即可。

但这一点并不能依靠简单的修改后缀名实现。简单来说,知乎在上传头像的时候实际上会在点击保存时,实际上会调用『HTMLCanvasElement.prototype.toBlob』,这相当于只截取了上传文件的第一帧,并只将截取后的转换为Blob对象。所谓的Blob对象简单来说就是一个二进制数据块。之后再上传到图床的数据实际上就是此处的Blob对象中的内容。这样就会导致即使你修改了后缀名,实际上也不能上传完整的webp文件,而只能上传其第一帧。

那么,我们可以怎么做呢?

知道以上原理之后,实现就很简单了。实际上我们只需要替换上传的Blob对象就行

有一个颇为邪道的实现方式是这样的:首先把webp文件传为base64的纯文本格式,然后再通过F12加载一个js脚本,从而实现把『HTMLCanvasElement.prototype.toBlob』上传数据替换为我们的webp文件。具体方式如下:

具体步骤

1,选择自己感兴趣的gif头像,并将其转化为webp格式。

转为webp格式主要是为了降低GIF文件的体积。这一步可以借助在线工具实现,比如:

GIF到WebP转换器

2,将webp格式的文件转化为base64格式。

我们知道图片的源文件一般都是个纯二进制文件,而base64则相当于直接将二进制文件用直接的64进制的纯文本来表示,这在很多不便上传二进制的场合,base64格式可以起到用纯文本传输图片/动图的作用。这一步主要是为了下一步中上传文件的方便。

这一点我们也可以借助在线工具实现:

webp 2 base64

3,借助以下脚本,将知乎网页提取的首帧替换为第二步转换的base64数据

这一步具体来说需要这么做:首先将以下脚本中data:image/webp;base64,XXXXXXXXXXXXXXXX部分替换为第二步中的『base64文本』。需要注意的复制粘贴的时候不要把后面的"; 也包含进去,这里的"是和前面成对出现的,不能缺失。

接着在借助base64ToBlob 将动图数据转化为Blob对象,从而实现我们的偷梁换柱

具体脚本如下:

// 1. 定义转换函数(将 Base64 转为原生 Blob)
function base64ToBlob(base64) {
    var parts = base64.split(';base64,');
    var contentType = parts[0].split(':')[1];
    var raw = window.atob(parts[1]);
    var rawLength = raw.length;
    var uInt8Array = new Uint8Array(rawLength);
    for (var i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i);
    }
    return new Blob([uInt8Array], {type: contentType});
}

// 2. 准备你的动图数据(填入你的长字符串)
var myRawData = "data:image/webp;base64,XXXXXXXX";
var myBlob = base64ToBlob(myRawData);

// 3. 替换 Blob 返回值(不使用 fetch,直接返回对象)
HTMLCanvasElement.prototype.toBlob = function(callback, type) {
    console.log("  拦截成功!已绕过 CSP 发送原始动图二进制流...");
    callback(myBlob);
};

// 4. 兼容旧版调用
HTMLCanvasElement.prototype.toDataURL = function() {
    return myRawData;
};

处理好脚本后,打开web端的『我的主页』,然后按F12 ,再在console中粘贴后的脚本,再按回车

具体来说,就是在下图粘贴以上内容,再按回车键

如果是第一次进行以上操作的话,还需要按浏览器提示输入对应的同意命令:

比如,这里的『allow pasting』。

这样,我们就能将上传的图片转变成完整的webp文件,从而实现动态头像。

4,最后,完成了上述准备工作后,我们再按正常的方式更换头像,就能得到动态头像了。

我们知道,第三步的实际功能是将常规流程中生成的Blob对象替换为我们选择的动图生成的Blob对象,并将其上传到知乎的图床。但这一步并没有实现主动上传,所以我们还需要借助常规换头像的流程来进行『借鸡下蛋』

也就是进行一个常规的换头像流程。随便上传任意一张图片都可以,因为都会被替换为base64文件的对应内容。

常见问题答疑:

Q1: 如何解决

Uncaught SyntaxError: Invalid or unexpected token

大概率是替换data:image/webp;base64,XXXXXXXXXXXXXXXX的时候把这一行最后的"; 删除了,在行末补上对应的引号和分号即可。这里的"是和前面成对出现的,不能缺失。

Q2: 如何解决

The string to be decoded is not correctly encoded

这主要是因为data:image/webp;base64,XXXXXXXX的前面指定数据类型的『data:image/webp;base64,』删掉了,恢复即可。

Q3:是否只能用来换头像

根据评论区 @起名困难症晚期 ,此方法还可以用来修改主页封面图片:

ps:知乎是否会修正这一替换方式?

某种意义上来说,这实际上是知乎图床的一个漏洞。对于我们上传的base64文件,知乎图床内部是否存在对于文件安全性的检查都是未知的。尤其是是作为头像,绝大多数其他用户都需要访问的情况下很容易成为一个可能的安全隐患。

从这个角度来说,知乎还是需要对于上传文件进行进一步的检查的。

但,我想说的是另外一点:既然知乎图床支持webp文件,那么到底为什么不愿意开放动态头像呢?

这一点在技术上完全不存在问题。

如果要修上传文件的bug的话,增加进一步校验之类的方式,我觉得于此同时还是应该官方开放动态头像

编辑于 2026-06-22 · 著作权归作者所有