前言

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,运算符选择等于,值选择为你的图片存储域名,直接确定即可。

新建触发规则

至于文件后缀限定条件,我觉得可有可无,因为函数本身已经判断过文件是否为图片了。不过如果图片本身有文件后缀,可以再次加上限定条件:pngjpgjpeg请不要带上.,否则函数将会无法触发。

对于 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 端一样。

最后修改:2025 年 10 月 06 日
如果觉得我的文章对你有用,请随意赞赏。