Unicode 发表于 2025-10-4 23:47:47

利用 EdgeOne 主要功能之一 边缘函数编写简易IP地址获取工具

# 1.关于 (https://edgeone.ai/redemption)
最近腾讯云搞了个 (https://edgeone.ai/redemption) ,搞得沸沸扬扬的,而边缘函数作为现代CDN普遍功能,在提升简单小功能的响应速度上具有非常大的帮助. 我没兑换码别找我.

# 2.定价
EdgeOne 免费试用版提供了 300w request/month,300w COREms/month 的免费配额,基本上和 Cloudflare 差不多.
!(https://cdn-sg-1.un1c0de.com:4434/myimgs/501ed3a2-83b4-499c-9da8-85de4652e788.png)

# 3.功能
这里我们主要讲 EdgeOne 的边缘函数功能, 其他的功能估计经常使用的人已经了如指掌了.

## 3.1.创建一个边缘函数
- 点击 `新建函数` 跳转到以下界面:
!(https://cdn-sg-1.un1c0de.com:4434/myimgs/cdddeb08-9385-4e97-af70-6a3029947e15.png)
- 点击下一步跳转到以下步骤:
!(https://cdn-sg-1.un1c0de.com:4434/myimgs/7ee4c4b1-efa8-4ac7-87b4-416fb2256191.png)
`函数名称`和`注释`只要合法,随便写,函数代码可以先按照他的不改,我们后期再做修改.
如果添加成功,那么会显示如下界面:
!(https://cdn-sg-1.un1c0de.com:4434/myimgs/af083ad6-f830-42e0-86d7-3281da9a48fa.png)
我们点击新增触发规则/或直接点击暂不需要.

## 3.2.创建触发规则
如果在上一步选择新增触发规则,那么就会来到以下界面:
!(https://cdn-sg-1.un1c0de.com:4434/myimgs/b0c987ee-f209-4c40-a713-a1e180e1458e.png)
- 匹配类型: 选择让指定的请求通过我们创建的函数
例如我们设置为 `HOST` `等于` `123.com`, 那么所有通过腾讯云EdgeOne的请求只要符合请求头/sni中 `HOST` 为 `123.com` 的请求都会通过我们设定的边缘函数

## 3.3.设置环境变量
回到函数管理->点击函数名进入函数管理->向下拉可以看到环境变量块.
!(https://cdn-sg-1.un1c0de.com:4434/myimgs/bef9dd47-6c7b-4201-946f-c466070dc473.png)
可以添加以文本或者JSON添加环境变量.作为示例,我这里添加一个 `default_output_key` 值为 `clientIp` 的变量用于演示.
**在添加完毕后,不要忘了点击右上角的 `部署` 进行变量的部署**

## 3.4.编写边缘JS代码
如果没有问题,那么你在他部署完毕后应该可以使用他提供的 `默认访问域名` 访问到你的 `Hello World` 边缘函数了.EdgeOne 提供了一些[示例代码](https://www.tencentcloud.com/zh/document/product/1145/52701?has_map=1)可以参考,同时也提供了(https://www.tencentcloud.com/zh/document/product/1145/52682?has_map=1)用于参考. 在这里我也创建一个自己的边缘函数示例代码,用于获取请求者IP信息,不过在介绍我的方法之前,先介绍以下主要的几个方法和类型:

### 3.4.1.addEventListener :fetch
注册事件监听器,是边缘函数的运行入口。`addEventListener` 仅支持注册一个事件监听器。当前仅支持 `fetch` 请求事件,通过注册 `fetch` 事件监听器,生成 `HTTP` 请求事件 `FetchEvent` ,进而实现对 `HTTP` 请求的处理。通俗来说就是你请求的入口,通过监听这个事件来做到回调,这部分和 `cloudflare` 的边缘函数有些许不同,但大体上是差不多的.

### 3.4.2.Request
根据 [官方文档](https://www.tencentcloud.com/zh/document/product/1145/52690) 对 `Request` 的描述, `Request` 代表 `HTTP` 请求对象,基于 Web APIs 标准 (https://developer.mozilla.org/en-US/docs/Web/API/Request) 进行设计. 我们要知道其中有 `eo` 这个属性(IncomingRequestEoProperties)对我我们编写一个IP查询函数十分重要.

### 3.4.3.Response
根据 [官方文档](https://www.tencentcloud.com/zh/document/product/1145/52691) , 我们可以知道 `Response` 代表 HTTP 响应,基于 Web APIs 标准 (https://developer.mozilla.org/en-US/docs/Web/API/Response) 进行设计。这个知不知道无所谓,反正就是用来做返回 `body` `header` 等功能.

### 3.4.3.编写主方法
当我们知道了如何调用和`request`的使用方法后,我们就能写出如下代码:
函数执行流程:
- 从环境变量中读取预先设置的 `default_output_key` 的值;
- 将所有能使用的ip信息存到 `full_info` 对象中;
- 获取URL信息,包括URL参数用于设定返回的body类型,是否返回美化后的Json,是否返回全部可用值,和指定返回的值;
- 将需要返回的值放入 `resp` 对象中;
- 根据 `ret_type` 决定返回类型,可选返回Json或者直接返回文本;
- 将数据编为JSON格式或者以 `key=value\n` 格式返回;

```javascript
async function handleRequest(request) {
let resp = {};
let full_info = {};
let response_body = "";
let select_all = false;
let stringify_settings = {
    visual_view : false
}
let headers = {
    "Access-Control-Allow-Origin": "*"
};
const keys_available = [
    "clientIp", "asn", "countryName", "countryCodeAlpha2",
    "countryCodeAlpha3", "countryCodeNumeric", "regionName",
    "regionCode", "cityName", "latitude", "longitude"
];
const env_default_key = env.default_output_key;
const key_alias = {
    ip: "clientIp",
    country: "countryName",
    lat: "latitude",
    lng: "longitude",
    city: "cityName",
    region: "regionName"
};
let selectedFields = || [
    "clientIp",
];
let ret_type = "text";
// 拷贝 ip 信息
full_info = {
    ...(request.eo?.clientIp && { clientIp: request.eo.clientIp }),
    ...(request.eo?.geo || {})
};;

// 获取URL信息
const urlInfo = new URL(request.url);
const params = urlInfo.searchParams;
if (params.keys().length > keys_available.length + 4) {
    return new Response("Too many params.\n", {status:403});
}
// 获取url参数
for (let of params.entries()) {
    switch (key) {
      case "type":
      ret_type = value;
      break;
      case "v":
      stringify_settings.visual_view = true;
      break;
      case "j":
      ret_type = "json";
      break;
      case "all":
      select_all = true;
      break;
      default:
      let rKey = key_alias || key;
      if ((keys_available.includes(rKey)) && !selectedFields.includes(rKey)) {
          selectedFields.push(rKey);
      }
      break;
    }
   
}

// 注入resp
if (select_all) {
    keys_available.forEach(key => {
    if (full_info !== undefined) {
      resp = full_info;
      }
    });
} else {
    selectedFields.forEach(key => {
      if (full_info !== undefined) {
      resp = full_info;
      }
    });
}


switch (ret_type) {
    case "json":
      response_body = stringify_settings.visual_view
      ?JSON.stringify(resp,null,2) + "\n"
      :JSON.stringify(resp) + "\n";
      
      headers["content-type"] = "application/json; charset=UTF-8";
      break;
    default:
    if (Object.keys(resp).length == 1) {
      response_body = resp] + "\n";
    } else {
      response_body = Object.entries(resp)
      .map(() => `${k}=${v}`)
      .join("\n") + "\n";
    }
      headers["content-type"] = "text/plain; charset=UTF-8";
}
return new Response(response_body,{ headers });
}

addEventListener('fetch', event => {
event.passThroughOnException();
event.respondWith(handleRequest(event.request));
});
```

# 4.Tips
- 3.4.3的主方法已经可用直接被用于边缘函数.即你可以直接将这个代码块全部写入保存并部署;如果出现访问之后返回空,请检查环境变量是否已成功设置 `default_output_key` 变量
- 该方法只是一个简单的示例, 理论上你可以用JS完成任何网页的构建,甚至可以只用边缘函数编写一个完整的Blog

# 5.Demo
访问地址: (http://myip.icu)
可选参数:
- `j`: 以JSON格式获取输出
- `v`: 以利于阅读的格式输出
- `all`: 获取所有信息
- `type`: 指定输出格式,可选: `json`,`text`
- `clientIp` or `ip`: 获取IP
- `asn`: 获取ASN号
- `countryName` or `country`: 获取国家名
- `countryCodeAlpha2`: 获取国家的 ISO-3611 alpha2 代码
- `countryCodeAlpha3`: 获取国家的 ISO-3611 alpha3 代码
- `countryCodeNumeric`: 获取国家的 ISO-3611 numeric 代码
- `regionName` or `region`: 获取区域名
- `regionCode`: 获取区域代码
- `cityName` or `city`: 获取城市名
- `latitude` or `lat`: 获取纬度
- `longitude` or `lng`: 获取经度

示例:
- 直接获取自己的IP地址: (http://myip.icu)
- 以Json可视化格式获取自己的IP地址所有信息: (http://myip.icu/?j&all&v)
- 以Json可视化格式获取自己的IP地址Country和IP: (http://myip.icu/?j&v&country)
- 用终端 curl 获取自己的ip地址: !(https://cdn-sg-1.un1c0de.com:4434/myimgs/e1926253-7b9a-4a33-8dad-8aab06a8e0ae.png)

# 6.后记
花了一个下午折腾了EdgeOne和IP优选,最后总结出来把EdgeOne设置成Cname + ns服务器放在华为云搞优选是真的很爽,如下:
!(https://cdn-sg-1.un1c0de.com:4434/myimgs/3bf8b937-07e8-454c-9b2b-7f8088e0493f.png)

日月明 发表于 2025-10-5 00:50:09

哇,这个不错,就不需要再设置源站了

cnsoft 发表于 2025-10-13 14:30:47

不错不错,那个环境变量没啥意义吧,删了相关两行也能运行

Unicode 发表于 2025-10-13 22:29:07

cnsoft 发表于 2025-10-13 14:30
不错不错,那个环境变量没啥意义吧,删了相关两行也能运行

因为我在代码里设置了默认key就是clientIp,删了也能运行.当然写这个是为了熟悉环境变量的
页: [1]
查看完整版本: 利用 EdgeOne 主要功能之一 边缘函数编写简易IP地址获取工具