利用 EdgeOne 边缘函数写入 Cloudflare IP GeoLocation 回源请求头以支持 WP-Statistics GeoIP
由 AI 生成的文章摘要
博主分享了一篇关于利用EdgeOne边缘函数实现Cloudflare IP Geolocation功能的文章。通过边缘函数和规则引擎的配合,成功模拟了Cloudflare提供的IP地理位置信息请求头,使WP-Statistics插件能够正常使用GeoIP功能。文章详细介绍了配置步骤,包括回源请求头的设置和边缘函数的编写,同时也提供了额外的图片格式转换优化方案。

利用 EdgeOne 边缘函数写入 Cloudflare IP GeoLocation 回源请求头以支持 WP-Statistics GeoIP

(标题很长,但这已经是我能想到的最短的叫法了)

前言

昨天群友发来一个 EdgeOne 领取免费版套餐兑换码的链接,竟然是 100% 中奖,每周 2000 份,每月更新(截止到现在也就兑了 350 份,基本是随便送了),一直很想把现有的国内腾讯云 CDN、国外 Cloudflare 的方案迁移到 EdgeOne 上,但奈何一直领不到免费版兑换码,这次终于如愿,遂赶紧噼里啪啦配置一顿,工作良好。

基本功能配置完毕,看了下 EdgeOne 有哪些额外功能,注意到 EdgeOne 支持携带客户端 IP 的地理位置信息回源,这让我想起来 Cloudflare 有一个名为 IP GeoLocation 的玩意儿,做了同样的事情,会把用户的国家码注入到 CF-IPCountry 请求头上给下游用(当然 EdgeOne 这里默认名称是 EO-Client-IPCountry)。

这让我想起来我的 WP-Statistics 插件也支持 Cloudflare IP GeoLocation 作为位置检测方法,于是探索了一下怎么让 EO 支持这套东西。本来以为简单配配规则引擎上的回源请求头就行了,结果完全没这么简单... 兜兜转转整了一天,终于探索出一套解决方案,遂分享出来(绝对不是水博客!)

解决方案

此方案也适用于其他需要在 EdgeOne 上使用 Cloudflare IP GeoLocation 同款请求头的需求。

首先,根据 WP-Statistics 源代码中的 CloudflareGeolocationProvider,可以看到 WP-Statistics 通过 isAvailableisBehindCloudflare 两个函数判断是否可以使用 Cloudflare IP GeoLocation 作为位置检测方式 —— 后者是初步判断,只有满足后者才能在设置中启用 IP GeoLocation;前者是最终判断,如果这个不为 true,即使你启用了 IP GeoLocation,也会被 fallback 到 MaxMind GeoIP 数据库的查询模式。

因此,取此二者函数所需要的请求头的并集,就得到了我们需要在 EO 上配置的回源请求头列表:

  • HTTP_CF_CONNECTING_IP
  • HTTP_CF_IPCOUNTRY
  • HTTP_CF_IPCONTINENT
  • HTTP_CF_REGION
  • HTTP_CF_IPCITY
  • HTTP_CF_IPLATITUDE
  • HTTP_CF_IPLONGITUDE
  • HTTP_CF_POSTAL_CODE

他们分别反映了访问者的连接 IP、所在国家、大洲、地区/州省、城市、经纬度、邮政编码(我不知道为什么他需要这个,而且事实上 EO 也提供不了这个,所以最后 Mock 了一个默认值)

但是很遗憾的是,EdgeOne 当前的规则引擎系统不支持配置地区和经纬度,所以这部分会交由边缘函数来做(别问我为什么边缘函数支持但是规则引擎不支持,另外也别问我为什么不全放到边缘函数上,规则引擎支持的大洲信息到边缘函数这儿又不支持了)。

于是,我们首先在规则引擎上配置如下修改回源请求头规则:

CF-IPCity: ${http.request.ip.city}
CF-IPCountry: ${http.request.ip.country}
CF-IPContinent: ${http.request.ip.continent}
CF-Connecting-IP: ${http.request.ip}

然后,在 EdgeOne 边缘函数上配置如下代码:

async function handleRequest(event) {
  const { request } = event;

  // 修改请求头
  request.headers.set('cf-iplongitude', request.eo.geo.longitude);
  request.headers.set('cf-iplatitude', request.eo.geo.latitude);
  request.headers.set('cf-region', request.eo.geo.regionName);
  request.headers.set('cf-region-code', request.eo.geo.regionCode);
  request.headers.set('cf-postal-code', '000000'); // EO 不支持邮政编码,我也不知道 WP Statistics 拿这个干什么用,所以返回一个 000000

  const response = await fetch(request);
  return response;
}

addEventListener('fetch', event => {
  // 当函数代码抛出未处理的异常时,边缘函数会将此请求转发回源站 
  event.passThroughOnException();
  event.respondWith(handleRequest(event));
});

配置好边缘函数的触发规则后应该就可以正常运行了。最后,注意边缘函数免费版是有用量限制的,小心被用爆。

后记:边缘函数很好玩,顺带做了个 AVIF 转换器

这功能挺好的,直接贴代码,如果用户浏览器支持 avif 就会转换成 avif,不支持就转换成 webp,否则就不转(注意配置完后记得限定触发规则为仅当文件后缀为 jpg, jpeg, png, 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';
  }

  // 支持 Avif 优先走 Avif
  if (accept && accept.includes('image/avif')) {
    option.eo.image.format = 'avif';
  }

  const response = await fetch(request, option);
  return response;
}

addEventListener('fetch', event => {
  // 当函数代码抛出未处理的异常时,边缘函数会将此请求转发回源站 
  event.passThroughOnException();
  event.respondWith(handleEvent(event));
});

配置好了以后网页访问速度有肉眼可见的提升,Lighthouse 的 Performance 分数也高了些,针不戳。

扫码关注 HikariLan's Blog 微信公众号,及时获取最新博文!


微信公众号图片
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇