hexo博客图片无法显示的问题解决方法

本文需要一些耐心阅读

许多朋友在初次使用hexo搭建博客时可能和我一样,都会遇到图片无法显示的问题。我在网上搜索了大量的资料,发现都无法解决我的问题,把_config.yml中的post_asset_folder 也设为 true 了,hexo-asset-image 插件也装了,但就是不行。后来找来找去,在 hexo-asset-image 中发现了端倪。本文最后将会从 hexo-asset-image 的源码上来分析问题,大家不要畏惧,这个插件的源码很简单,都是一些字符串操作。

追根溯源

首先,在一个网页中,图片加载不出来有两种情况,1. 图片服务器宕机,2. 图片URL错误。第一种情况属于个人博客服务器的问题,不在我们的讨论范围内,我们的重点是,图片的URL。

首先要理解hexo的原理,我们给hexo提供markdown文件,hexo生成静态网页,在hexo生成HTML网页的时候,就是图片URL写入的时候,而 hexo-asset-image 插件就是在hexo每生成一个HTML网页时,修改其中<img> 标签的 src 属性,从而能引用到正确的图片

然后就是 post_asset_folder 属性,这个属性为true时,运行 hexo new "passage name" 创建文章时,hexo会在 source/_posts/ 目录下创建一个和文章的markdown文件名相同的文件夹,这个文件夹就hexo存放我们的markdown中图片的地方。为了和hexo的图片文件夹保持同步,我们还需要对markdown编辑器的文件路径进行一些调整,我使用的是Typora,来到Typora的设置中,找到图像选项,设置为以下这样:

image-20241027150234573

如果你的文章现在已经有了一些图片,那么你可能需要修改一下图片的文件夹名,和文章中引用图片的markdown语句,来确保引用了正确的图片。

除此之外,这个属性对于 hexo-asset-image 这个插件来说至关重要,我们来看看 hexo-asset-image 的源码:

image-20241027142127258

大家注意到了吗,在上图的if语句中,有:config.post_asset_config 没错,当post_asset_config这个属性为true时,才会执行 hexo-asset-image 插件的一系列逻辑!所以 post_asset_config 这个属性是一定要设置为 true 的,否则插件不会生效。

你还需要注意一个博客配置文件_config.yml的属性:permalink 。这个属性定义了你的每一篇文章的URL是怎样的,默认值是这样的:

1
permalink: :year/:month/:day/:title/

例如,我的博客网站地址是 www.example.com , 那么我在2024年10月10日写的标题为test的文章的地址就是: www.example.com/2024/10/10/test ,我们后面的配置都会按照上面的这个格式来,建议大家设为和我一样

查看你的网页图片src属性

在进行接下来的步骤之前,你需要确保_config.yml文件中:post_asset_folder 已设置为truepermalink 已设置为 :year/:month/:day/:title/

别急着安装 hexo-asset-image 插件

既然图片渲染不出来,那么看看它的src属性是啥不就行了嘛,这里有两种方法,第一种是直接在浏览器的F12菜单中查看,第二种是去到你的博客目录的 public/:year/:month/:day/:title/ 没错,就是我们前文通过permalink所设置的日期路径,打开这个文件夹后,你会发现你的图片就在这里面,除此之外还有一个HTML文件,这个文件就是hexo根据你的md文件渲染出来的HTML网页。

我们打开这个HTML文件,查看img标签的src属性,发现是这样的:

image-20241027144359153

安装 hexo-asset-image 插件

这很明显不对!我们期望的路径应该是/2024/10/27/test/image-20241027143951576.png,这个时候我们再装上hexo-asset-image 插件:npm install hexo-asset-image --save ,然后运行:

1
2
3
hexo clean
hexo g
hexo s # 你如果想在云端测试,请运行 hexo d 将博客部署到你的服务器上去

再来看看区别:

image-20241027144951023

可以看到路径更加牛头不对马嘴了,这里解释一下,撰写这篇文章时,我的博客是用IP地址部署的,也就是说没有域名,我的IP地址后两位就是82,而82前面那个英文句点自然就是IP地址中的分割点了,从这里就可以看出,是hexo-asset-image这个插件有问题,把图片映射到了错误的路径。

解决问题:修改hexo-asset-image的源码

源码可以在<你的博客目录>/node_modules/hexo-assets-image/index.js找到

这里我直接将代码的关键部分贴出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// http://stackoverflow.com/questions/14480345/how-to-get-the-nth-occurrence-in-a-string
function getPosition(str, m, i) {
return str.split(m, i).join(m).length;
}

hexo.extend.filter.register('after_post_render', function(data){
var config = hexo.config;
if(config.post_asset_folder){
var link = data.permalink;
var beginPos = getPosition(link, '/', 3) + 1;
var appendLink = '';
// In hexo 3.1.1, the permalink of "about" page is like ".../about/index.html".
// if not with index.html endpos = link.lastIndexOf('.') + 1 support hexo-abbrlink
if(/.*\/index\.html$/.test(link)) {
// when permalink is end with index.html, for example 2019/02/20/xxtitle/index.html
// image in xxtitle/ will go to xxtitle/index/
appendLink = 'index/';
var endPos = link.lastIndexOf('/');
}
else {
var endPos = link.lastIndexOf('.');
}
link = link.substring(beginPos, endPos) + '/' + appendLink;
// 省略......

首先我们来分析一下其中的各个变量代表什么含义,首先就是 var link = data.permalink 这句,我虽然没有了解过如何编写hexo插件,但是结合我们刚才在配置文件中看到的 permalink 属性就可以猜出来,data.permalink 实际上就是文章的URL,而且是包括了域名的URL,我们可以尝试将其打印出来看看:console.log("permalink: " + link)

注意这个打印语句并非是在你每次访问文章网页的时候打印到浏览器的F12菜单的控制台里面的,而是在你每次运行 hexo g 命令时,输出到命令行里面的,所以要想看到输出,我们就必须要运行 hexo g ,运行后,你会发现输出了很多行语句,hexo-asset-image 这个插件的原理就是在hexo生成完静态网页后,修改其中的imgsrc属性,所以你有多少篇文章,这个语句就会被执行多少次!我的输出是这样的:

image-20241027151910500

理解了data.permalink是什么,我们来继续读代码,可以看到又调用了一个 getPosition 函数,这个函数是定义在代码最开头的,我们来看看:

1
2
3
function getPosition(str, m, i) {
return str.split(m, i).join(m).length;
}

使用了字符串的split方法,这个方法的第二个参数是用来限制分割后的列表长度的,例如:

1
"hello,world,are,you,ok".split(",", 3) // ["hello", "world", "are"]

根据我的URL,经过它传入的参数调用这个函数,最终的beginPos的值应该是:20,也就是指向 /2024处的斜杠的位置

好的我们继续往下看,它的注释写的很清楚,就是处理URL中有无index子串或者index.html子串,我们重点来看else的部分(因为我的博客URL没有index或者index.html关键字),可以看到这部分代码出现了明显的错误!怎么能直接去找最后一个".“的位置呢,这也是我们前面看到的src属性出现了:”.82"的字样的原因,只需要将这行代码改成下面这样就行了:

1
var endPos = link.length + 1;

没错就是这么简单,直接让他指向URL的末尾就可以了

再继续看:

1
link = link.substring(beginPos, endPos)  + appendLink;

这行代码就是在得出最后的图片路径了,在我的博客配置下,appendLink变量是一个空字符串。

不妨来输出一下这个link变量:console.log("final link: " + link)

image-20241027153915622

成功了!

这时候再次运行hexo g,查看生成的HTML中img的src属性:

image-20241027154149773

路径终于正确了!

至此,博客上面的图片就能正常加载出来了