前言
Edgeone 横空出世,不少博客都写上几篇相关的文章,也都用上了免费的服务。虽然 EdgeOne 还不错,但用起来还是没有 Cloudflare 方便,所以我只把静态资源放在了 EdgeOne 加速,包括我的图床(实际上是我的 R2 存储桶)。
为了保证原图存储,我的图床在上传之时没有进行图片格式转换和缩放,避免以后需要用到原图时还要重新寻找图片上传。但是过大的图片也实在是考验用户的网速,影响访问体验。
EdgeOne 虽然有直接的图片处理服务,但是还要升级个人版,对于一个白嫖用户来说实在是不合适。
刚好 EdgeOne 边缘函数 有一定量的免费额度(边缘函数请求数 300万次,边缘函数 CPU Time 300万毫秒),对于我这个小小小图床那是绰绰有余的。
EdgeOne 官方文档 提供了示例函数,包含图片自适应 WebP
与图片自适应缩放
,但是二者并不是合在一起的,或许是为了促进“图片处理服务”的使用吧。如果没有示例函数,对于函数的书写还是有点费劲的,还要把原本那么多文档喂给 ChatGPT。不过现在就很简单了。
我们可以借助ChatGPT把两个示例函数进行合并,实现图片自适应转换与缩放,并且不用改变原有图片的链接!这是最为方便的。
分函数
图片自适应 WebP
在文档的最佳实践里面还有一版根据浏览器转换不同格式的,我觉得太过麻烦,所以直接自适应转换 WebP 就好了。
async function handleEvent(event) {
const { request } = event;
// 获取客户端支持的图片类型
const accept = request.headers.get('Accept');
const option = { eo: { image: {} } };
// 检查客户端是否支持 WebP 格式的图片,若不支持响应原图
if (accept && accept.includes('image/webp')) {
option.eo.image.format = 'webp';
}
const response = await fetch(request, option);
return response;
}
addEventListener('fetch', event => {
// 当函数代码抛出未处理的异常时,边缘函数会将此请求转发回源站
event.passThroughOnException();
event.respondWith(handleEvent(event));
});
图片自适应缩放
经过体验,我感觉图片自适应缩放比单纯的图片质量压缩好,图片自适应缩放可以让质量更小,并且不太影响观感,因为图片的尺寸也更小了。
addEventListener('fetch', event => {
// 当函数代码抛出未处理的异常时,边缘函数会将此请求转发回源站
event.passThroughOnException();
event.respondWith(handleEvent(event));
});
async function handleEvent(event) {
const { request } = event;
const urlInfo = new URL(request.url);
const userAgent = request.headers.get('user-agent');
// 请求非图片资源
if (!/\.(jpe?g|png)$/.test(urlInfo.pathname)) {
return fetch(request);
}
// 移动端图片宽度
let width = 480;
const isPcClient = isPc(userAgent);
// PC 端图片宽度
if (isPcClient) {
width = 1280;
}
// 图片缩放
const response = await fetch(request, {
eo: {
image: {
width,
}
}
});
// 设置响应头
response.headers.set('x-ef-client', isPcClient ? 'pc' : 'mobile');
return response;
}
// 请求客户端类型判断
function isPc(userAgent) {
const regex = /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i;
if(regex.test(userAgent)) {
return false;
}
return true;
}
合函数:图片格式自适应转换与缩放
我自然是不会合并的,那就交给 ChatGPT 吧。通过图片格式自适应转换与压缩,一箭双雕,再也不用担心博客图片加载慢的问题了。
函数代码
addEventListener('fetch', event => {
// 当函数代码抛出未处理的异常时,将请求转发回源站
event.passThroughOnException();
event.respondWith(handleEvent(event));
});
async function handleEvent(event) {
const { request } = event;
const urlInfo = new URL(request.url);
const userAgent = request.headers.get('user-agent');
// 请求非图片资源,直接返回
if (!/\.(jpe?g|png)$/i.test(urlInfo.pathname)) {
return fetch(request);
}
// 判断客户端类型
const isPcClient = isPc(userAgent);
// 移动端图片宽度
let width = isPcClient ? 1280 : 480;
// 获取客户端支持的图片格式
const accept = request.headers.get('Accept');
const imageOptions = {};
if (accept && accept.includes('image/webp')) {
imageOptions.format = 'webp';
}
// 图片请求
const response = await fetch(request, {
eo: {
image: {
width,
...imageOptions
}
}
});
// 设置响应头
response.headers.set('x-ef-client', isPcClient ? 'pc' : 'mobile');
return response;
}
// 判断是否为 PC 客户端
function isPc(userAgent) {
const regex = /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i;
return !regex.test(userAgent);
}
功能说明 By ChatGPT
- PC 客户端宽度 1280,移动端 480。
- 支持 WebP 格式的客户端返回 WebP,否则使用原格式。
- 非图片请求直接返回原始资源。
- x-ef-client 响应头标识客户端类型。
部署函数
新建函数规则
在 EdgeOne 后台 进入站点,在左侧边栏选择边缘函数
,新建一个函数,随意选择一个模版,把函数代码替换成上面的合函数
,然后创建并部署。
新建触发规则
进入刚才创建的那个函数,点击新建触发规则
,匹配类型选择HOST
,运算符选择等于
,值选择为你的图片存储域名,直接确定即可。
至于文件后缀限定条件,我觉得可有可无,因为函数本身已经判断过文件是否为图片了。不过如果图片本身有文件后缀,可以再次加上限定条件:png
、jpg
、jpeg
。请不要带上.
,否则函数将会无法触发。
对于 Gravatar 的镜像站来讲,文件后缀就没有必要限定了,因为 Gravatar 的头像链接是不带文件后缀的,如果限定了文件后缀将会无法转换为 WebP 格式。
似乎这个函数代码对于 Gravatar 镜像站无效,可能是因为在函数代码中检测了一次图片类型,所以即使在前端的我触发条件
没有限制文件后缀,依然无法转换。
对于这个问题,可以使用不进行文件后缀判断的函数代码,并把文件后缀判断的限定移到前端的触发条件
中。我们可以对Gravatar 镜像域名单独设定一个触发条件
,在前端也不判断文件后缀。
// 没有作用,请不要使用
async function handleEvent(event) {
const { request } = event;
const userAgent = request.headers.get('user-agent');
const isPcClient = isPc(userAgent);
let width = isPcClient ? 1280 : 480;
const accept = request.headers.get('Accept');
const imageOptions = {};
if (accept && accept.includes('image/webp')) {
imageOptions.format = 'webp';
}
try {
const response = await fetch(request, {
eo: {
image: {
width,
...imageOptions
}
}
});
response.headers.set('x-ef-client', isPcClient ? 'pc' : 'mobile');
return response;
} catch (e) {
// 如果不是图片或处理失败,返回原始请求
return fetch(request);
}
}
好像怎么改都没用,可是我记得之前的只转换格式代码是可以的。不管了,反正 Gravatar 头像 本身不是很大,转不转换区别不大,开个缓存就好了。
测试效果
现在来访问部署完函数的站点图片,虽然链接的末尾还是原本的文件后缀,但是打开检查工具,在网络中找到这张图片,就会发现文件类型已经变成了image/webp
。
再点击一下图片,就会发现图片尺寸变小了,没有原来那么大了,但依然是很清晰的。
最后把图片下载下来,发现图片的大小小了很多,并且下载下来的文件后缀为webp
。
我也来这里放一个测试链接:https://cdn.cll.tw/img/2025/08/1755540774.jpg
原本大小为 7.7 MB 的图片,现在已经变为 562 KB 了,加载起来都非常丝滑。
参考资料
图片自适应 WebP:https://edgeone.ai/zh/document/57423?product=edgedeveloperplatform
图片自适应缩放:https://edgeone.ai/zh/document/54770?product=edgedeveloperplatform
通过边缘函数实现自适应图片格式转换:https://edgeone.ai/zh/document/54768?product=edgedeveloperplatform
结语
EdgeOne 也变成大善人了......
通过 EdgeOne 边缘函数,可以让图片自适应格式转换与缩放,浏览体验大大提升,也不会影响原图的存储,未来可操作性很强。
不过目前博客只有大图片放在了图床上,截图什么的还是存储在本地。虽然有 Typecho 直接上传到兰空图床的插件,但感觉还是存在本地保险。
等一会还是迁移一下,双端备份也比较保险呢,速度也能提升一下。截图什么的就不压缩了,清清晰晰的比什么都好。
好像有一个问题,自适应图片在第一次访问的时候需要进行转换,所以很慢。但之后就能快起来了呢。
还有一个问题就是移动端的缩放太狠了,只考虑了显示大小,却没有考虑放大后的大小。建议将移动端的自适应宽度改为和 PC 端一样。