通过CloudFront Functions边缘函数实现访问跳转

本文介绍如何使用CloudFront Functions实现访问跳转。

一、背景

针对特定网站发布的URL跳转需求,例如:

  • 访问/abc/test,则自动跳转为/abc/test.html
  • 访问/abc/,则自动跳转为/abc/index.html

以上需求,在CloudFront的图形控制台上操作不能实现。因为CloudFront仅支持到设置根目录的默认页面例如/index.html的需求,但是不能针对特定子目录设置默认页面。由此可使用CloudFront的边缘算力来提供。关于CDN边缘侧算力Lambda@Edge和CloudFront Functions两个边缘侧计算函数功能的对比,可以参考这篇博客里边有对比表格。

对于访问请求跳转,可通过修改Request请求的URI实现,因此用CloudFront Functions更加轻量级的,是比Lambda@Edge延迟小、且成本更低的方案。CloudFront Functions的计费是每100万次运行收费0.1USD。

下边开始配置。

二、配置和验证访问

1、创建函数

首先进入CloudFront服务的控制台中,点击左侧的Function函数按钮。点击右上角的创建按钮。如下截图。

在创建函数页面,输入函数的名称,例如取名Redirect,然后选择版本为cloudfront-js-2.0。然后点击创建函数按钮。如下截图。

函数创建完成。此时页面下方出现了Build标签页,这里可输入代码。如下截图。

Development的标签页下,粘贴要提交的代码。

function handler(event) {
    var request = event.request;
    var uri = request.uri;
    var clientIP = event.viewer.ip;
    
    // Check whether the URI is missing a file name.
    if (uri.endsWith('/')) {
        request.uri = '/index.html';
        console.log({'ClientIP': clientIP});
    } 
    // Check whether the URI is missing a file extension.
    else if (!uri.includes('.')) {
        request.uri += '.html';
    }

    return request;
}

注:以上代码会输出客户端IP地址作为日志,并保存到CloudWatch Log Groups。

点击右上角的Save changes按钮保存设置。如下截图。

2、测试函数

本文需求有两个,一个是访问任意目录(即请求以/为结尾),则自动跳转到/index.html,另一个需求是输入不含扩展名的请求则自动补全.html扩展名。下边分别测试。

保存成功后,切换到Test测试标签页,然后在URL Path位置输入要测试的路径。最后点击右上角的Test function按钮。如下截图。

将页面向下滚动,可以看到返回的测试结果是成功地跳转到/index.html,这与预期的一致。如下截图。

接下来测试另一个需求,输入输入不含扩展名的请求,测试是否自动补全。这里在URL Path位置输入要测试的请求是/abc/myfile。最后点击右上角的Test function按钮。如下截图。

将页面向下滚动,可以看到返回的测试结果是成功地跳转到/abc/myfile.html,这与预期的一致。如下截图。

测试通过后,开始发布。

3、与CloudFront发布点绑定

进入函数的第三个标签页Publish发布标签页。此时标签页会提示unpublished未发布字样。点击右下角Publish function发布函数。如下截图。

函数发布完毕后,向下滚动页面,找到下方Associated distrubtion绑定发布点位置,点击添加。如下截图。

在下拉框中,选择要绑定的发布点。在请求类型Event type位置选择Viewer request,表示来自客户端请求抵达CloudFront时候,运行函数修改请求。在Cache behavior位置选择默认的Default。如下截图。

发布成功后,回到函数页面,可以看到当前函数的状态是Updating更新中。此时CloudFront会在全球的450+边缘节点加载新发布的函数。如下截图。

等待3-5分钟后,发布完成。

4、使用CURL发起测试验证函数运行正常

现在可以使用curl测试了。

首先测试跳转需求1,也就是访问任意的目录跳转到/index.html。例如请求

curl https://yourname.com/abc01/def02/test1/ 

此时返回的将是https://yourname.com/index.html页面的内容。

继续测试跳转需求2,输入不含扩展名的请求则自动补全.html扩展名。

curl https://yourname.com/abc01/def02/test2

此时返回的将是https://yourname.com/abc01/def02/test2.html页面的内容。

至此CloudFront Function函数部署完成。

三、CloudFront Function的监控和日志

1、查看函数运行次数

进入CloudFront服务界面,在左侧菜单中,点击Monitoring菜单。点击右侧标签栏的CloudFront Functions,在下方的函数清单中,找到要查看的函数选中之,点击右上角的View metrics按钮。如下截图。

在当前界面下,即可看到函数的运行次数、错误计数等信息。如下截图。

具体的各项监控参数的定义,可参考本文末尾的官方文档。

2、查看CloudFront Functions日志

与Lambda@Edge查看日志的时候要定位用户访问的POP点、以及Regional Cache Center所在地这种方式有所不同,CloudFront Functions查看日志更为简单。CloudFront Functions始终在美国东部(弗吉尼亚北部)区域 (us-east-1) 中创建Cloudwatch日志流,无论用户访问的是哪一个边缘节点。日志组名称的格式为/aws/cloudfront/function/FunctionName,其中FunctionName是您在创建函数时为函数指定的名称。日志流名称的格式为YYYY/M/D/UUID

需要注意的是,日志输出必须显式的打开。如果CloudFront Functions函数代码包含console.log()语句,这些日志会发送到CloudWatch Loggroups中。如果代码中没有console.log()语句,则不会输出日志。本文的Demo代码已经包含了一个日志输出,在进入特定If循环中,会打印日志。

下边开始查看日志。

进入美东1N.Virginia弗吉尼亚北部区域的的CloudWatch服务,从左侧的菜单中找到Log groups日志组,点击进入。在右侧的搜索过滤框中,输入关键字Cloudfront,然后即可列出所有函数的日志组。点击其中一个进入。如下截图。

在日志组界面,点击第一个标签页log streams。然后下方会列出多条日志流。通过时间戳找到最新的一个,点击进入。如下截图。

在日志中可看到START/END标记,在之间的就是打印日志。本文记录的日志是访问CloudFront的客户端IP地址。如下截图。

至此查看日志完成。

四、小结

本文描述了如何配置一个Cloudfront Functions函数实现对特定URL的跳转。结合使用场景,有如下几点建议:

  • 尽量使用CloudFront Functions实现,复杂函数才使用Lambda@Edge实现。因为CloudFront Functions可运行在450+ POP点;而Lambda@Edge只能运行在13个Regional Cache Center,二者网络延迟有差异;
  • Cloudfront Functions百万次调用费用$0.1,而Lambda@Edge调用是$0.6,成本差六倍;
  • 因为Cloudfront Functions是直接绑定到一整个CDN发布点,因此函数注意测试充分完毕在上线,以免其中的扩展名、目录等逻辑判断错误导致整个发布点故障;
  • Cloudfront Functions的测试界面按测试按钮,将不会给CloudWatch Log Groups中打日志;发起测试时候,测试的日子就打在测试页面的下方;
  • 函数代码中需要显式用console.log()语句打日志,日志统一输出到美东1(us-east-1)弗吉尼亚北部(N.Virginia)区域的CloudWatch Log Groups中,开头为/aws/cloudfront的就是
  • 建议将需要Cloudfront Functions和不需要Cloudfront Functions的内容通过不同的域名,分离到两个发布点;这是因为函数一旦绑定到发布点,本发布点所有的调用都会call这个函数,即便函数中通过if/else进行逻辑判断后没有改动访问请求,这样也是会被计为运行次数加1;因此将不需要调用函数的内容通过不同的域名,独立分配到另外的发布点,由此会显著降低函数调用次数。

五、参考文档

CloudFront Functions函数计费

https://aws.amazon.com/cloudfront/pricing/?nc1=h_ls

url-rewrite-single-page-apps

https://github.com/aws-samples/amazon-cloudfront-functions/blob/main/url-rewrite-single-page-apps/index.js

CloudFront Functions 日志

https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/edge-functions-logs.html#cloudfront-function-logs

查看默认的 CloudFront Functions 指标

https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/viewing-cloudfront-metrics.html#monitoring-console.cloudfront-functions

CloudFront Functions 日志

https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/edge-functions-logs.html#cloudfront-function-logs