EdgeOne 边缘函数 - 构建边缘网关

目前,各大主流厂商都推出了自己的边缘 Serverless 服务,如 CloudFlare Workers、 Vercel EdgeRuntime 等;腾讯云 EdgeOne 边缘函数提供了部署在边缘节点的 Serverless 代码执行环境,只需编写业务函数代码并设置触发规则,即可在靠近用户的边缘节点上弹性、安全地运行代码。

一、前言

在许多业务场景中,需要对请求或响应进行处理,以实现特定的功能或优化用户体验。通常,这些操作在网关层完成。使用 EdgeOne 边缘函数实现请求改写或重定向,构建边缘网关,可以帮助开发者可以更加灵活地控制请求流程,同时减轻网关服务的负担。

二、边缘网关

使用 EdgeOne 边缘函数构建轻量边缘网关服务,有如下优势:

  1. 全球网络:边缘网关可以在用户地理位置附近处理请求,减少延迟,提高响应速度。

  2. 高性能:边缘函数基于 V8 引擎打造,几乎没有冷启动延迟。

  3. 成本效益:高效利用边缘算力,可以有效降低业务成本。

  4. 服务集成:在边缘网关层面集成第三方服务,如身份验证、自定义缓存策略等,无需修改前后端服务。

  5. 零维护:EdgeOne 负责维护底层基础设施,开发者可以专注于编写和代码,不必担心服务器的维护和运维。

  6. 即时更新:代码更新可以在全球范围内快速生效。

三、代码示例

1. 代码示例旨在展示边缘函数的能力,仅列举常见方案的基本实现;
2. 文章中涉及的代码可私信获取;

3.1 请求重定向

请求重定向在实际业务场景中是一个常见的操作,例如:网站或服务正在进行维护,需要将请求重定向到一个维护通知页面。仅需几行代码,便可实现边缘重定向。

3.1.1 Fetch Redirect

使用 fetch 第三方域名的方式,实现隐式重定向:

const REDIRECT = 'https://tencent.com/';

async function handleEvent(event) {
  const { request } = event;
  const url = new URL(request.url);

  // 直接 fetch 第三方域名
  const res = await fetch(`${REDIRECT}${url.pathname}${url.search}`, request);
  event.respondWith(res);
}

addEventListener('fetch', handleEvent);

localhost:8080 隐式重定向到 https://tencent.com

3.1.2 302 Redirect

还可以使用 302 的方式,实现显式重定向:

const REDIRECT = 'https://www.tencentcloud.com/';

async function handleEvent(event) {
  const url = new URL(event.request.url);

  if (url.pathname === '/') {
    // 返回 302 响应
    event.respondWith(Response.redirect(REDIRECT));
  }

  return;
}

addEventListener('fetch', handleEvent);

注意:
通常情况下,站点级别的重定向使用 302 形式,接口级别的重定向使用  fetch 的形式,根据实际情况选择不同的重定向方式;

3.2 日志上报

使用边缘函数,拦截请求/响应,将指定数据上报到 腾讯云 CLS 日志服务平台:

import { AsyncClient, Content, LogGroup, LogItem, PutLogsRequest } from '@tencent/edgefunction-cls-sdk';

/** CONFIG START */

const TENCENT_SECRET_ID = 'xxxxx';
const TENCENT_SECRET_KEY = 'xxxxx';

const CLS_END_POINT = 'xxxxx';
const CLS_TOPIC_ID = 'xxxxx';

/** CONFIG END */

const clsAsyncClient = new AsyncClient({
  endpoint: CLS_END_POINT,
  secretId: TENCENT_SECRET_ID,
  secretKey: TENCENT_SECRET_KEY,
  ....
});

async function clsUpload(data) {
  ...
  const logContent = new Content('__CONTENT__', JSON.stringify(data));
  ...
  const clsRequest = new PutLogsRequest(CLS_TOPIC_ID, logGroup);
  const clsResponse = await clsAsyncClient.PutLogs(clsRequest);
  ...
}

async function doClsUpload(request) {
  try {
    const data = await request.clone().text();
    await clsUpload(data);
  } catch (err) {
    ...
  }
}

async function handleRequest(event) {
  const { request } = event;
  const contentType = request.headers.get('content-type') || '';

  if (contentType.includes('application/json') || contentType.includes('text/plain')) {
    // 用于通知边缘函数等待 Promise 完成,可延长事件处理的生命周期,不阻塞 fetch(request) 的返回。
    event.waitUntil(doClsUpload(request));
  }

  return;
}

addEventListener('fetch', handleRequest);

上面的代码使用 event.waitUntil() 实现了在不阻塞响应的情前提下,将请求体中携带的数据上报到 腾讯云 CLS 日志服务,,可以在 腾讯云控制台 - 日志服务 - 检索分析 查看:

3.3 性能监控

在边缘函数中,通过修改响应体的方式,插入 腾讯云 RUM 前端性能监控 相关代码,统一处理页面监控的相关逻辑,简化操作流程:

...
async function handleEvent(event) {
  const { request } = event;
  const response = await fetch(request);

  if (response.status !== 200 || response.headers.get('Content-Type') !== 'text/html') {
    return response;
  }

  const aegisScript = `<script src="https://tam.cdn-go.cn/aegis-sdk/latest/aegis.min.js"></script>
<script>
  const aegis = new Aegis({
    id: '${AEGIS_ID}',
    ...
  });
</script>
`;
  let resBody = await response.clone().text();
  resBody = resBody.replace('</title>', `</title>\n${aegisScript}`);

  const modifiedRes = new Response(resBody, response);
  event.respondWith(modifiedRes);
}

addEventListener('fetch', handleEvent);

源站响应的 HTML 文件被注入了 aegis SDK 的相关代码:

性能监控相关数据可以在 腾讯云控制台 - 前端性能监控 - 页面性能 查看:

3.4 i18n 国际化

我们可以在边缘函数函数中,根据客户所在国家和地区,以及该地区使用的语言,实现站点国际化。

该功能可以使用  ef-flow-sdk 实现。
...

function getOfficialLanguages(countryCodeAlpha2) {
  const territoryInfo = cldr.supplemental.territoryInfo?.[countryCodeAlpha2];
  if (territoryInfo) {
    const languages = territoryInfo.languagePopulation;
    const langs = Object.keys(languages)
      .filter(lang => languages[lang]._officialStatus === 'official')
      .map(lang => {
        const qValue = languages[lang]._populationPercent / 100;
        return `${lang};q=${qValue.toFixed(2)}`;
      });
    return langs;
  }
  return [];
}

export function generateAccLangByGeo(request) {
  const { countryCodeAlpha2 } = request?.eo?.geo || {};

  let acceptLanguage = null;
  if (countryCodeAlpha2) {
    const officialLangs = getOfficialLanguages(countryCodeAlpha2).join(',');
    acceptLanguage = officialLangs || '';
  }

  // 如果没有成功匹配(没有命中规则 / 没有 geo),则生成一个默认头部 en
  return acceptLanguage || 'en';
}

const langConfig = {
  origin: {
    title: 'CSR - REACT',
  },
  localization: [
    {
      lang: 'zh',
      title: '中文标题',
    },
  ],
};

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

  if (new URL(request.url).pathname !== '/') {
    return;
  }

  const response = await fetch(request);
  if (response.status !== 200 || response.headers.get('Content-Type') !== 'text/html') {
    return event.respondWith(response);
  }

  const originRes = response.clone();
  const acceptLanguage = request.headers.get('Accept-Language') || generateAccLangByGeo(request);
  const parsedAccLang = parser.parse(acceptLanguage);

  let hit = null;
  for (const acclang of parsedAccLang) {
    const { code, region } = acclang;
    const rule = langConfig.localization.find(rule => {
      const parsedRule = rule.lang.split('-');
      if (parsedRule[1]) {
        return parsedRule[0] === code && parsedRule[1] === region;
      }
      return parsedRule[0] === code;
    });

    if (code && rule) {
      hit = rule;
      break;
    }
  }

  if (hit) {
    let retBody = await response.text();
    retBody = retBody.replaceAll(new RegExp(langConfig.origin.title, 'ig'), hit.title);

    return event.respondWith(new Response(retBody, originRes));
  }
  return;
}

addEventListener('fetch', handleEvent);

3.5 地域封禁

在边缘函数中,可以基于 GEO 信息,实现地理位置的封禁。

// 国家封禁列表 伊朗、古巴、朝鲜、叙利亚
const CLOSURE_COUNTRY_CODE_LIST = ['IR', 'CU', 'KP', 'SY'];
// 地区封禁列表 克里米亚地区 UA-43、顿巴斯地区 (顿涅茨克 UA-14、卢甘斯克 UA-09)
const CLOSURE_REGION_CODE_LIST = ['UA-14', 'UA-09', 'UA-43'];

function checkClosureGeo(request) {
  const { countryCodeAlpha2, regionCode } = request?.eo?.geo || {};

  // 判断 countryCode
  if (countryCodeAlpha2 && CLOSURE_COUNTRY_CODE_LIST.includes(countryCodeAlpha2)) {
    return true;
  }

  // 判断 regionCode
  if (regionCode && CLOSURE_REGION_CODE_LIST.includes(regionCode)) {
    return true;
  }

  return false;
}

function handleEvent(event) {
  if (checkClosureGeo(event.request)) {
    event.respondWith(new Response('Forbidden', { status: 403 }));
  }
  return;
}

addEventListener('fetch', event => {
  event.passThroughOnException();
  handleEvent(event);
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/754578.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

免费分享:2021年全国30米分辨率最大NDVI数据集(附下载方法)

气候变化及其对陆地生态系统的影响已成为核心议题&#xff0c;备受社会各界的瞩目。植被作为地理环境的关键构成部分&#xff0c;是气候变迁与人文活动对环境影响的敏感晴雨表。其中&#xff0c;归一化植被指数&#xff08;NDVI&#xff09;可以作为衡量地面植被状况的重要指标…

【C语言】解决C语言报错:Invalid Pointer

文章目录 简介什么是Invalid PointerInvalid Pointer的常见原因如何检测和调试Invalid Pointer解决Invalid Pointer的最佳实践详细实例解析示例1&#xff1a;未初始化的指针示例2&#xff1a;已释放的指针示例3&#xff1a;返回局部变量的指针示例4&#xff1a;野指针 进一步阅…

①常用API----Math

public static int abs(int a) // 返回参数的绝对值 public static double ceil(double a) // 返回大于或等于参数的最小整数 public static double floor(double a) // 返回小于或等于参数的最大整数 public static int round(f…

ubuntu22.04编译安装tesseract

1、 为什么用自己编译安装&#xff0c;而不采用apt安装&#xff1f; 由于tesseract有很多依赖包&#xff0c;直接用deb包或者rpm包等安装包安装很复杂&#xff0c;不一定能成功安装。 2、安装基本的依赖包 sudo apt update sudo apt install g autoconf automake libtool pkg…

float8格式

产生背景 在人工智能神经元网络中&#xff0c;一个参数用1字节表示即可&#xff0c;或者说&#xff0c;这是个猜想&#xff1a;因为图像的颜色用8比特表示就够了&#xff0c;所以说&#xff0c;猜想神经元的区分度应该小于256。 数字的分配 8比特有256个码位&#xff0c;分为…

AWS云计算平台:全方位服务与实践案例

摘要 在数字化浪潮的推动下&#xff0c;云计算已成为企业转型的强大引擎。AWS作为云计算的先锋&#xff0c;不仅提供了一系列强大的基础设施服务&#xff0c;更是在人工智能领域不断探索和创新。本文将带您领略AWS的全方位服务&#xff0c;并透过实际案例&#xff0c;感受其在…

ROS2创建服务用RCLCPP实现

1.创建服务提供者service_server_01.cpp #include "example_interfaces/srv/add_two_ints.hpp" #include "rclcpp/rclcpp.hpp" class ServiceServer01 : public rclcpp::Node { public: ServiceServer01(std::string name) : Node(name) { RCLCPP_…

应对铜价飙升,慧能泰推出超高性价比240W五芯线专用eMarker芯片

全球铜价仍然居高不下&#xff0c;以前买电线论捆算&#xff0c;现在巴不得论‘克’珍藏。这年头&#xff0c;换根充电线都得三思而后行&#xff0c;考虑的不是颜色款式&#xff0c;而是‘这条线的铜含量&#xff0c;值几个涨停板&#xff1f;’ 说实话&#xff0c;铜价上涨&a…

[AHK]微信表情快捷输入

需求&#xff1a; 希望在电脑上微信聊天时用键盘快捷输入常用表情。 工具&#xff1a; AutoHotkey v1 使用说明&#xff1a; 微信中按空格显示热键提示窗口&#xff0c;输入键盘序列后&#xff0c;按空格输出相应表情 配置&#xff1a; 源代码&#xff1a; /** 脚本&…

Python之父推荐!Star 60k!深入CPython内核:揭秘内部实现细节

都说 Python 是人工智能的“天选”语言&#xff0c;为什么呢&#xff1f; 可能很多读者都知道&#xff0c;Python 的解释器是用 C 语言写的&#xff0c;所以其实我们在谈论 “Python” 的时候&#xff0c;99.9% 的情况说的就是 “CPython”&#xff01; CPython 是目前最流行的…

一文弄懂线性回归模型

1、引言 今天&#xff0c;我们将深入探讨机器学习中的三个关键概念&#xff1a;线性回归、代价函数和梯度下降。这些概念构成了许多机器学习算法的基础。起初&#xff0c;我决定不写一篇关于这些主题的文章&#xff0c;因为它们已经被广泛涉及。不过&#xff0c;我改变了主意&…

小白快速入门canvas画海报

小编以微信小程序原生语言举例 wxml页面&#xff1a; <canvas type"2d" id"myCanvas" style"width:375px;height:667px;"></canvas> js页面&#xff1a; import drawQrcode from ../../../utils/qrcode/weapp.qrcode.esmdata: {…

IDEA SpringBoot整合SpringData JPA(保姆级教程,超详细!!!)

目录 1. 简介 2. 创建SpringBoot项目 3. Maven依赖引入 4. 修改application.properties配置文件 5. Entity实体类编写 6. Dao层接口开发 7. 测试接口开发 8. 程序测试 1. 简介 本博客将详细介绍在IDEA中&#xff0c;如何整合SpringBoot与SpringData JPA&#xff0c;以…

EtherCAT笔记(四)——EtherCAT数据帧结构

EtherCAT数据包含2B的数据头和44~1948B的数据区。数据区由多个子报文组成。由于EtherCAT本身是通过以太网数据帧的形式传输&#xff0c;因此其协议帧中会携带以太网的帧头。 其中&#xff0c;解释如下&#xff1a; &#xff08;1&#xff09;以太网数据帧头&#xff1a;EtherC…

AUTOSAR NvM模块(一)

NvMBlockDescriptor [ECUC_NVM_00061] 用于存储所有特定于块的配置参数的容器。对于每个非易失性随机存取存储器&#xff08;NVRAM&#xff09;块&#xff0c;应该指定这个容器的一个实例。 NvMBlockCrcType 定义了NVRAM块的CRC数据宽度。根据Autosar标准&#xff0c;此参数…

KVB外汇:澳元/美元、澳元/纽元、英镑/澳元的走势如何?

摘要 本文对近期澳元/美元、澳元/纽元、英镑/澳元的技术走势进行了详细分析。通过对关键支撑位和阻力位的分析&#xff0c;我们可以更好地理解澳元在不同货币对中的表现。随着全球经济形势的变化&#xff0c;各国央行的货币政策对外汇市场的影响也愈发明显。本文旨在帮助投资者…

观成科技:证券行业加密业务安全风险监测与防御技术研究

摘要&#xff1a;解决证券⾏业加密流量威胁问题、加密流量中的应⽤⻛险问题&#xff0c;对若⼲证券⾏业的实际流量内容进⾏调研分析&#xff0c; 分析了证券⾏业加密流量⾯临的合规性⻛险和加密协议及证书本⾝存在的⻛险、以及可能存在的外部加密流量威 胁&#xff0c;并提出防…

用GAN生成奖杯

数据集链接&#xff1a;https://pan.baidu.com/s/19Uxc2ELiMG3acUtLeSTDTA?pwdwsyw 提取码&#xff1a;wsyw 我设置的图片大小为128*128&#xff0c;如果内存爆炸可以将batch_size调小&#xff0c;epoch我设置的2000&#xff0c;我感觉其实1000也够了。代码如下&#xff1a; …

信创认证 | Smartbi Insight V11成功适配申威3231处理器

在信息技术飞速发展的浪潮中&#xff0c;软硬件的深度融合与协同发展已成为推动行业创新的关键因素。 近日&#xff0c;思迈特商业智能与数据分析软件[简称&#xff1a;Smartbi Insight]V11在统信服务器操作系统V20和中电科申泰信息科技有限公司产品申威3231处理器环境下完成适…

CAN和CANFD数据写入.asc文件的dll

因为工作需要&#xff0c;需要做一些硬件不是CANoe的上位机&#xff08;比如说周立功CAN,NI-CAN&#xff09;&#xff0c;上位机需要有记录数据的功能&#xff0c;所以用Qt制作了一个记录数据的dll&#xff0c;方便重复使用&#xff08;因为有的客户指定了编程软件&#xff0c;…